redux笔记
redux用来管理state
action→state
reducer将action与state串起来。
例如
function visibilityFilter(state = ‘SHOW_ALL’, action) {
if (action.type === ‘SET_VISIBILITY_FILTER’) {
return action.filter;
} else {
return state;
}
}
function todos(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return state.concat([{ text: action.text, completed: false }]);
case 'TOGGLE_TODO':
return state.map((todo, index) =>
action.index === index ?
{ text: todo.text, completed: !todo.completed } :
todo
)
default:
return state;
}
}
再开发一个 reducer 调用这两个 reducer,进而来管理整个应用的 state:
function todoApp(state = {}, action) {
return {
todos: todos(state.todos, action),
visibilityFilter: visibilityFilter(state.visibilityFilter, action)
};
}
三大原则
- 单一数据源
- state只读
- 使用纯函数来执行修改
数组型state
state只读:reducer中返回新的state时只能返回一个新的而不是修改原state,对于数组型的state可以使用concat()
或者slice()
创建一个新的数组,例:
const todos = [
'Go to the store',
'Clean the house',
'Cook dinner',
'Learn to code',
];
const immutableReducer = (state = todos, action) => {
switch(action.type) {
case ADD_TO_DO:
// 不要在这里改变 state
return state.concat(action.todo)
default:
return state;
}
};
或者ES6的新解决办法,扩展运算符:let newArray = [...myArray];
此时newArray是myArray的一个新的复制,如果想要添加新的元素可以[... myArray,'new value']
,删出数组元素使用slice:
return [
...state.slice(0, action.index),
...state.slice(action.index + 1, state.length)
];
删除数组下标为index的元素
对象型state
对于state为对象时,使用Object.assign()
const defaultState = {
status: 'offline',
community: 'freeCodeCamp'
};
const immutableReducer = (state = defaultState, action) => {
switch(action.type) {
case 'ONLINE':
// 不要在这里改变 state 否则测试会失败。
return Object.assign({}, state, { status: "online" });
default:
return state;
}
};
const wakeUp = () => {
return {
type: 'ONLINE'
}
};
const store = Redux.createStore(immutableReducer);
store,action,reducer
Redux store 是应用程序状态的唯一真实来源。
Redux 是一个状态管理框架,更新状态是其核心任务之一
在 Redux 中,所有状态更新都由 dispatch action 触发,action 只是一个 JavaScript 对象,其中包含有关已发生的 action 事件的信息
Redux store 接收这些 action 对象,然后更新相应的状态。有时,Redux action 也会携带一些数据。
创建 action 后要将 action 发送到 Redux store,以便它可以更新其状态,action creator 只是一个返回动作的 JavaScript 函数,换句话说,action creator 创建表示动作事件的对象
store.dispatch()
讲action creator与store联系起来 例:
const store = Redux.createStore(
(state = {login: false}) => state
);
const loginAction = () => {
return {
type: 'LOGIN'
}
};
// 在这里 dispatch action
store.dispatch(loginAction())
reducer函数:在一个 action 被创建并 dispatch 之后,Redux store 需要知道如何响应该操作
reducer将state和action作为参数,并且它总是返回一个新的state。
例子:
const defaultState = {
login: false
};
const reducer = (state = defaultState, action) => {
// 修改此行下方的代码
if (action.type=='LOGIN') {
return {
login:true
}
} else return defaultState
// 修改此行上方的代码
};
const store = Redux.createStore(reducer);
const loginAction = () => {
return {
type: 'LOGIN'
}
};//这是action creator
store.dispatch(loginAction()) //通过dispatch将store与action联系起来,通过createStore创建store与reducer的联系
store dispatch分发action动作,reducer说明action完成了什么动作,createStore吧动作放在这个store里
传递参数
const ADD_NOTE = "ADD_NOTE";
const notesReducer = (state = "Initial State", action) => {
switch (action.type) {
// change code below this line
case ADD_NOTE:
return action.text;
// change code above this line
default:
return state;
}
};
const addNoteText = note => {
// change code below this line
return {
type: ADD_NOTE,
text: note
};
// change code above this line
};
const store = Redux.createStore(notesReducer);
console.log(store.getState());
store.dispatch(addNoteText("Hello!"));
console.log(store.getState());
组合多个reducer
需要一个rootreducer来装下小的reducer,combineReducers()
const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';
const counterReducer = (state = 0, action) => {
switch(action.type) {
case INCREMENT:
return state + 1;
case DECREMENT:
return state - 1;
default:
return state;
}
};
const LOGIN = 'LOGIN';
const LOGOUT = 'LOGOUT';
const authReducer = (state = {authenticated: false}, action) => {
switch(action.type) {
case LOGIN:
return {
authenticated: true
}
case LOGOUT:
return {
authenticated: false
}
default:
return state;
}
};
const rootReducer = Redux.combineReducers({
count: counterReducer,
auth: authReducer
});
const store = Redux.createStore(rootReducer);
异步
Redux Thunk中间件
如果要使用 Redux Thunk 中间件,请将其作为参数传递给Redux.applyMiddleware()
。然后将此函数作为第二个可选参数提供给createStore()
函数,然后,要创建一个异步的 action,你需要在 action creator 中返回一个以dispatch
为参数的函数。在这个函数中,你可以 dispatch action 并执行异步请求。
const REQUESTING_DATA = 'REQUESTING_DATA'
const RECEIVED_DATA = 'RECEIVED_DATA'
const requestingData = () => { return {type: REQUESTING_DATA} }
const receivedData = (data) => { return {type: RECEIVED_DATA, users: data.users} }
const handleAsync = () => {
return function(dispatch) {
// 在这里 dispatch 请求的 action
setTimeout(function() {
let data = {
users: ['Jeff', 'William', 'Alice']
}
// 在这里 dispatch 接收到的数据 action
}, 2500);
}
};
const defaultState = {
fetching: false,
users: []
};
const asyncDataReducer = (state = defaultState, action) => {
switch(action.type) {
case REQUESTING_DATA:
return {
fetching: true,
users: []
}
case RECEIVED_DATA:
return {
fetching: false,
users: action.users
}
default:
return state;
}
};
const store = Redux.createStore(
asyncDataReducer,
Redux.applyMiddleware(ReduxThunk.default)
);
简单解释就是,异步请求分为了两个action。一是提出数据申请requesting,二十数据receive,将这两个动作作为修改state的action。分别处理。
计数器
const INCREMENT = "INCREMENT"; // define a constant for increment action types
const DECREMENT = "DECREMENT"; // define a constant for decrement action types
// define the counter reducer which will increment or decrement the state based on the action it receives
const counterReducer = (state = 0, action) => {
switch (action.type) {
case INCREMENT:
return state + 1;
case DECREMENT:
return state - 1;
default:
return state;
}
};
// define an action creator for incrementing
const incAction = () => {
return {
type: INCREMENT
};
};
// define an action creator for decrementing
const decAction = () => {
return {
type: DECREMENT
};
};
// define the Redux store here, passing in your reducers
const store = Redux.createStore(counterReducer);
redux-react
React Redux 提供的 API 有两个关键的功能:Provider和connect
Provider需要两个 props:Redux store 和 APP 应用的子组件。用于 APP 组件的Provider可这样定义:
<Provider store={store}>
<App/>
</Provider>
连接redux与react:connect
const addMessage = (message) => {
return {
type: 'ADD',
message: message
}
};
const mapStateToProps = (state) => {
return {
messages: state
}
};
const mapDispatchToProps = (dispatch) => {
return {
submitNewMessage: (message) => {
dispatch(addMessage(message));
}
}
};
class Presentational extends React.Component {
constructor(props) {
super(props);
}
render() {
return <h3>This is a Presentational Component</h3>
}
};
const connect = ReactRedux.connect;
// 请在本行以下添加你的代码
const ConnectedComponent=connect(mapStateToProps, mapDispatchToProps)(Presentational)
上面这段代码中mapDispatchToProps
负责分发action,mapStateToProps
负责映射state,connect函数负责将组件与前面两者联系起来
连接到 Redux 的组件命名为Presentational,这个命名不是任意的,这样的术语通常是指未直接连接到 Redux 的 React 组件,他们只负责执行接收 props 的函数来实现 UI 的呈现。
以下折叠为将react与redux联系起来的代码
// Redux:
const ADD = 'ADD';
const addMessage = (message) => {
return {
type: ADD,
message: message
}
};
const messageReducer = (state = [], action) => {
switch (action.type) {
case ADD:
return [
...state,
action.message
];
default:
return state;
}
};
const store = Redux.createStore(messageReducer);
// React:
const Provider = ReactRedux.Provider;
const connect = ReactRedux.connect;
// 请在本行以下添加你的代码
class Presentational extends React.Component {
constructor(props) {
super(props);
this.state = {
input: '',
}
this.handleChange = this.handleChange.bind(this);
this.submitMessage = this.submitMessage.bind(this);
}
handleChange(event) {
this.setState({
input: event.target.value
});
}
submitMessage() {
this.props.submitNewMessage(this.state.input)
this.setState({
input: '',
});
}
render() {
return (
<div>
<h2>Type in a new Message:</h2>
<input
value={this.state.input}
onChange={this.handleChange}/><br/>
<button onClick={this.submitMessage}>Submit</button>
<ul>
{this.props.messages.map( (message, idx) => {
return (
<li key={idx}>{message}</li>
)
})
}
</ul>
</div>
);
}
};
// 请在本行以上添加你的代码
const mapStateToProps = (state) => {
return {messages: state}
};
const mapDispatchToProps = (dispatch) => {
return {
submitNewMessage: (message) => {
dispatch(addMessage(message))
}
}
};
const Container = connect(mapStateToProps, mapDispatchToProps)(Presentational);
class AppWrapper extends React.Component {
render() {
return (
<Provider store={store}>
<Container/>
</Provider>
);
}
};