redux
是 react
的状态管理工具,全局组件可共享 store
的状态。
store
state
都是以一个对象树的形式存在一个单一的 store
中state
的办法就是触发 action
newState
reducer
就是用来编写专门的纯函数,决定每个 action
如何改变 state
dispatch
触发一个 action
的时候,会遍历当前 store
里注册的 reducer
state
的一个动作dispatch
去触发一个action
,从而修改 state
dispatch(action)
reducer
产生 newState
subscribe
触发通知react
和 redux
react-redux
引入 Provider
, 用 Provider
传递 store
import React from 'react';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import todoApp from './reducers';
import App from './components/App';
let store = createStore(todoApp);
export default function () {
return (<Provider store={store}>
<App />
</Provider>);
}
store
,就通过 connect
将 state
和 dispatch
注入到 props
中import { connect } from 'react-redux';
// connect 高阶组件,将 state 和 dispatch 注入到组件 props 中
const VisibleTodoList = connect(
mapStateToProps,
mapDispatchToProps
)(TodoList);
export default VisibleTodoList;
redux
默认只能处理同步 action
action
,就需要使用中间件// 同步 action
export const addTodo = text => {
// 返回 action 对象
return {
type: 'ADD_TODO',
id: nextTodoId++,
text
};
};
// 异步 action
export const adTodoAsync = text => {
// 返回函数,其中有 dispatch 参数
return (dispatch) => {
// ajax 异步获取数据
fetch(url).then(res => {
// 执行异步 action
dispatch(addTodo(res.text));
});
};
};
// logger 实现
let next = store.dispatch;
store.dispatch = function dispatchAndLog(action) {
console..log('dispatching', action);
next(action);
console.log('next state', store.getState());
}
hash
模式:默认,如 http://abc.com/#/user/10
H5 history
模式:需要server 端支持,如 http://abc.com/user/20
import React from 'react';
import { HashRouter as Router, Switch, Route } from 'react-router-dom';
import React from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
function RouterComponent() {
return (
<Router>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/project/:id">
<Project />
</Route>
<Route path="*">
<NotFound />
</Route>
</Switch>
</Router>
);
}
function RouterComponent() {
return (
<Router>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/project/:id">
<Project />
</Route>
<Route path="*">
<NotFound />
</Route>
</Switch>
</Router>
);
}
import React from 'react';
import { Link, useParams } from 'react-router-dom';
function Project() {
// 获取 url 参数,如 '/project/100'
const { id } = useparaqms();
console.log('url param id', id);
return (
<div>
<Link to="/">首页</Link>
</div>
);
}
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import React, { Suspense, lazy } from 'react';
const Home = lazy(() => import(';'routes/Home'));
const About = lazy(() => import(';'routes/About'));
const App = () => (
<Router>
<Suspense fallback={<div>Loading...</div>}>
<Switch>
<Route exact path="/" component={home} />
<Route path="/about" component={About} />
/Switch>
</Router>
);
redux
中 action
如何处理异步?
redux-thunk
或者 redux-saga
redux-thunk
可以带来哪些好处?
dispatch
只能用来触发 reducer
更新 state
;dispatch
的 action
只能是一个对象dispatch
进行二次封装,加一些自己的逻辑在里面,可以进行异步处理,其实最终还是触发了 reducer
来更新 state
;可以 dispatch
一个函数。ajax
请求或者其他异步操作,配合 redux
直接使用,即使不用 thunk
,也是可以实现功能的,为什么还要用 redux-thunk
?
ajax
,就得放在页面或者 react
组件中触发请求,然后再把请求结果 dispatch
到 store
中,这样就把数据层拆分了。view
层(即 页面或者 React
组件)是分离的,即便没有 view
层,数据层也应该保持独立。redux
的单向数据流。View
中触发一个动作,然后 dispatch
一个 action
去执行 reducer
,修改 state
,然后 subscribe
触发通知去更新 View
dispatch
的时候可以做一些额外的操作,然后再去触发 action
执行 reducer
修改 state
。redux
是通过比较一个状态前后是否有改变来决定页面是否更新的,而比较状态是否改变是通过浅层比较的,因为深度比较很耗费性能,所以有效的解决方案就是做一个规定,当无论发生任何变化时,都要返回一个新的对象,没有变化时返回旧的对象。