rogerxu / rogerxu.github.io

Roger Xu's Blog
3 stars 2 forks source link

React #27

Open rogerxu opened 7 years ago

rogerxu commented 7 years ago

adam-golab/react-developer-roadmap: Roadmap to becoming a React developer in 2018

React 技术栈系列教程 - 阮一峰的网络日志

rogerxu commented 7 years ago

React

Getting Started with React – An Overview and Walkthrough – Tania Rascia A Complete Beginner's Guide to React - DEV Community 👩‍💻👨‍💻

Pros

Why We Moved From Angular to React

rogerxu commented 7 years ago

Component

var HelloMessage = React.createClass({
  propTypes: {
    title: React.PropTypes.string.isRequired,
  },

  getDefaultProps: function () {
    return {
      title : 'Hello World'
    };
  },

  render: function() {
    return <h1>Hello {this.props.name}</h1>;
  }
});

Details

rogerxu commented 7 years ago

Flux

React and Flux

It allows you to model your application in terms of Actions, Stores, and Views. It also has a part known as Dispatcher to manage actions and allow you to model dependencies between different calls.

image https://survivejs.com/eccd841152209cbde7cbe79d4e72ec2e.png

Flux Dataflow

Cyclical Flux dataflow https://survivejs.com/1e3f32400990086df1776cd97a7ea6ce.png

image http://7tszky.com1.z0.glb.clouddn.com/FonZpI0A0bUAcv1jwAhJdALdqDOj

Dispatcher

Store

Action

image http://7tszky.com1.z0.glb.clouddn.com/FulidOFq7yfm-fyPHy9qm50JDu-K

Disadvantages

rogerxu commented 7 years ago

Alt

In Alt, you'll deal with actions and stores. The dispatcher is hidden, but you will still have access to it if needed. Compared to other implementations, Alt hides a lot of boilerplate.

Alt Instance

app/libs/alt.js

Connecting Alt with Views

Normally state management solutions provide two parts you can use to connect them with a React application. These are a Provider component and a connect higher order function (function returning function generating a component). The Provider sets up a React context.

Provider

app/index.jsx

import Provider from './components/Provider';

ReactDOM.render(
  <Provider><App /></Provider>,
  document.getElementById('app')
);

connect

connect allows us to attach specific data and actions to components.

app/libs/connect.jsx

(stateFunc, actions, target = App) => Connect

app/components/App.jsx

export default connect(stateFunc)(App);

Stores

app/stores/NoteStore.js

export default class NoteStore {
  constructor() {
    this.notes = [];
  }
}

app/components/App.jsx

Now App component can consume data from store instead of state.

class App extends React.Component {
  render() {
    const {notes} = this.props;
  }
}

export default connect(({ notes }) => ({
  notes
}))(App);

Actions

app/actions/NoteAction.js

export default alt.generateActions('create', 'update', 'delete');

app/stores/NoteStore.js

export default class NoteStore {
  constructor() {
    this.bindActions(NoteActions);

    this.notes = [];
  }

  create(note) {
    this.setState({
      notes: this.notes.concat(note)
    });
  }
}

app/components/App.jsx

class App extends React.Component {
  addNote = () => {
    this.props.NoteActions.create({});
  }
}
rogerxu commented 7 years ago

Redux

Comparison

浅谈 React、Flux 与 Redux - 腾讯Web前端 IMWeb 团队社区 | blog | 团队博客 flux vs redux vs mobx

Concept

Redux 入门教程(一):基本用法 - 阮一峰的网络日志

Three Principles

vs. Flux

Data Flow

image https://cdn-images-1.medium.com/max/1000/1*kDO26wU8yMn0Xq7crphztA.png

  1. call store.dispatch(action)
  2. The Redux store calls the reducer function you gave it.
  3. The root reducer may combine the output of multiple reducers into a single state tree.
  4. The Redux store saves the complete state tree returned by the root reducer.

Actions

const action = {
  type: 'ADD_TODO',
  payload: 'Learn Redux'
};

Action Creators

actions/sample-actions.js

import { createAction } from 'redux-actions';

export const MAKE_BARK = 'MAKE_BARK';
export const makeBark = createAction(MAKE_BARK, () => true);

Use bound action creator to automatically dispatch actions

const boundAddTodo = (text) => dispatch(addTodo(text));
boundAddTodo(text);

bindActionCreators

bindActionCreators()

Reducers

const reducer = (state = initialState, action) => {
  // ...
  return new_state;
};

Combine Reducers

import { combineReducers } from 'redux';

const rootReducer = combineReducers({
  todos,
  filter,
);

Put all top-level reducers into a separate file ../reducers/index.js, export each reducer function, and use import * as reducers to get the as an object with their names as the keys.

import { combineReducers } from 'redux';
import * as reducers from './reducers';

const rootReducer = combineReducers(reducers);

Immutable

reducers/sample-reducer.js

import Immutable from 'immutable';

const initialState = Immutable.Map({
  hasBarked: false,
});

const sampleReducer = (state = initialState, action) => {
  switch (action.type) {
    case SAMPLE:
      return state.set('hasBarked', action.payload);
    default:
      return state;
  }
};

export default sampleReducer;
import { createStore } from 'redux';
import { combineReducers } from 'redux-immutable';

Store

There is only one single store in a Redux application.

import { createStore } from 'redux';
import reducer from './reducers';

const store = createStore(reducer);

State

const state = store.getState();

Dispatcher

store.dispatch(action);

Workflow

image http://7tszky.com1.z0.glb.clouddn.com/FqwrgoH93cl8a5f3oFc0XZL7waBQ

store = dispatcher + reducer

Redux Workflow http://zhenhua-lee.github.io/img/react/redux.png

image

rogerxu commented 7 years ago

Redux + Middlewares

Redux 入门教程(二):中间件与异步操作 - 阮一峰的网络日志

Middleware

Middlewares are used to redefine store.dispatch method to make it accept action other than an object. For example, function or Promise.

applyMiddleware

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import createLogger from 'redux-logger';
import rootReducer from './reducers';

const logger = createLogger();

const store = createStore(
  rootReducer,
  initialState,
  applyMiddleware(thunk, promise, logger)
);

redux-thunk

actions.js

import fetch from 'isomorphic-fetch';

export const REQUEST_POSTS = 'REQUEST_POSTS';
function requestPosts(topic) {
  return {
    type: REQUEST_POSTS,
    topic
  };
}

export const RECEIVE_POSTS = 'RECEIVE_POSTS';
function receivePosts(topic, json) {
  return {
    type: RECEIVE_POSTS,
    topic,
    posts: json.data.children.map(child => child.data),
    receivedAt: Date.now(),
  };
}

function fetchPosts(topic) {
  // return function instead of action object for thunk middleware
  return (dispatch) => {
    // start request
    dispatch(requestPosts(topic));

    // return Promise object as the return value of the dispatch method
    return fetch(`service/${topic}.json`)
      .then(response => response.json())
      .then(json => dispatch(receivePosts(topic, json)));
  };
}

function shouldFetchPosts(state, topic) {
  const posts = state.postsByTopic[topic];

  if (!posts) {
    return true;
  } else if (posts.isFetching) {
    return false;
  } else {
    return posts.didInvalidate;
  }
}

exports function fetchPostsIfNeeded(topic) {
  return (dispatch, getState) => {
    if (shouldFetchPosts(getState(), topic)) {
      // dispatch a thunk from thunk
      return dispatch(fetchPosts(topic));
    } else {
      // let the calling code know there is nothing to wait for
      return Promise.resolve();
    }
  };
}
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';

const store = createStore(
  rootReducer,
  initialState,
  applyMiddleware(thunk)
);

redux-promise

const fetchPosts = (dispatch, topic) => new Promise(function (resolve, reject) {
  // start request
  dispatch(requestPosts(topic));

  // return Promise object as the return value of the dispatch method
  return fetch(`service/${topic}.json`)
    .then(response => response.json())
    .then(json => dispatch(receivePosts(topic, json)));
});
import { createStore, applyMiddleware } from 'redux';
import promise from 'redux-promise';
import rootReducer from './reducers';

const store = createStore(
  rootReducer,
  initialState,
  applyMiddleware(promise)
);
rogerxu commented 7 years ago

React + Redux

Redux 入门教程(三):React-Redux 的用法 - 阮一峰的网络日志

Presentational Component

Container Component

connect()

import { connect } from 'react-redux';

const VisibleTodoList = connect(
  mapStateToProps,
  mapDispatchToProps,  
)(TodoList);

Provider component

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);
rogerxu commented 7 years ago

React-Router

React Router 使用教程 - 阮一峰的网络日志

rogerxu commented 6 years ago

MobX

Introduction | MobX

image http://zhenhua-lee.github.io/img/state-mge/mobx.png

Comparison

How We Ditched Redux for MobX – Skillshare Writings – Medium

image https://cdn-images-1.medium.com/max/1000/1*QZ8X8IZfm7IPkZj0iyRC7w.png

MobX vs Redux with React: A noob’s comparison and questions

react 的数据管理方案:redux 还是 mobx? - 腾讯Web前端 IMWeb 团队社区 | blog | 团队博客

使用 mobx 时,借鉴了 redux 架构的优点:

不同点:

Mobx 思想的实现原理,及与 Redux 对比

Redux:

Mobx:

rogerxu commented 6 years ago

React Context API

React Context API: Managing State with Ease

Comparison

Redux vs. The React Context API

rogerxu commented 5 years ago

DVA

Vuex与Redux对比 - hyupeng1006的博客 - CSDN博客

DVA,对React-Redux进行了封装,并结合了Redux-Saga等中间件,而且使用了model概念,也相当于在React-Redux的基础上针对web应用开发做了优化。(个人认为DVA框架的开发者可能是对VUEX有所借鉴的)

image https://zos.alipayobjects.com/rmsportal/PPrerEAKbIoDZYr.png

rogerxu commented 3 years ago

Hooks

React – A JavaScript library for building user interfaces

weekly/079.精读《React Hooks》.md at v2 · dt-fe/weekly

对React Hooks的一些思考 - 知乎

State

import React, { useState } from 'react';

useState is a React function that returns two things: a value and a function to change that value.

const [date, setDate] = useState(initialDate);

function tick() {
  setDate(new Date());
}

<p>It is {date.toLocaleTimeString()}.</p>

Effect

import React, { useEffect } from 'react';
useEffect(() => {
  // mount hook
  const timerId = setInterval(() => tick(), 1000);

  // return unmount hook
  return () => clearInterval(timerId);
});

Handling Events

<button onClick={handleClick}>
  Activate Lasers
</button>

Lists and Keys

const todoItems = todos.map((todo) =>
  <li key={todo.id}>
    {todo.text}
  </li>
);
rogerxu commented 3 years ago

Context

Context – React

React Hooks vs. Redux: Do Hooks and Context replace Redux? - LogRocket Blog

Context is designed to share data that can be considered “global” for a tree of React components.

React.createContext(defaultValue)

theme-context.js

import React from 'react';

// Create a context for the current theme (with "light" as the default).
export const ThemeContext = React.createContext('light');

Context.Provider

Every Context object comes with a Provider React component that allows consuming components to subscribe to context changes.

Accepts a value prop to be passed to consuming components that are descendants of this Provider.

Use a Provider to pass the data to the tree. Any component can read it, no matter how deep it is.

<ThemeContext.Provider value={theme}>
  <Toolbar />
</ThemeContext.Provider>

useContext hook

All consumers that are descendants of a Provider will re-render whenever the Provider’s value prop changes.

themed-button.js

import { useContext } from 'react';
import { ThemeContext } from './theme-context';

function ThemedButton() {
  const theme = useContext(ThemeContext);

  return <Button theme={theme} />;
}

export default ThemedButton;

Updating Context

Pass a function down through the context to allow consumers to update the context.

theme-context.js

import React from 'react';

export const ToggleThemeContext = React.createContext(() => {
});

theme-toggler-button.js

import { useContext } from 'react';
import { ThemeContext, ToggleThemeContext } from './theme-context';

function ThemeTogglerButton() {
  const theme = useContext(ThemeContext);
  const toggleTheme = useContext(ToggleThemeContext);

  return (
    <button
      onClick={toggleTheme}>
      Toggle Theme
    </button>
  );
}

export default ThemeTogglerButton;

app.js

import { useState} from 'react';
import { ThemeContext, ToggleThemeContext, themes } from './theme-context';
import ThemeTogglerButton from './theme-toggler-button';

function App() {
  const [theme, setTheme] = useState(themes.light);

  function toggleTheme() {
    setTheme(currentTheme => {
      return currentTheme === themes.dark
        ? themes.light
        : themes.dark
    });
  }

  return (
    // have to be nested Providers
    <ThemeContext.Provider value={theme}>
      <ToggleThemeContext.Provider value={toggleTheme}>
        <Content />
      </ToggleThemeContext.Provider>
    </ThemeContext.Provider>
  );
}

function Content() {
  return (
    <div>
      <ThemeTogglerButton />
    </div>
  );
}

ReactDOM.render(<App />, document.root);