安装其他的babel依赖(babel真心是一个全家桶,具体的介绍去官网看吧..我后面再总结,这里反正全装上就是了): npm install --save babel-polyfill - Babel includes a polyfill that includes a custom regenerator runtime and core.js. This will emulate a full ES6 environment
npm install --save-dev babel-plugin-transform-runtime - Externalise references to helpers and builtins, automatically polyfilling your code without polluting globals.
npm install --save-dev babel-preset-es2015 - Babel preset for all es2015 plugins.
npm install --save-dev babel-preset-react - Strip flow types and transform JSX into createElement calls.
npm install --save-dev babel-preset-stage-2 - All you need to use stage 2 (and greater) plugins (experimental javascript).
const List = (props) => { // we're using an arrow function and const variable type, a ES6 features
return (
I'm a list!!!
)
};
export default List;
在 ToDoApp.js引入 List用List 组件替换 List goes here.,写法为 .现在在浏览器中就可以看到"I'm a list!!!"
现在我们来把这个变成真实的列表,首先就需要通过props传递数据,我们把这个从state中获取的数据list通过命名为listItems的props传递,写作: ,现在 List 已经通过props获取了 ToDoApp中的数据。
然后在 List 组件中我们需要render一个列表,先用下面的jsx代码代替:
{
list // this is a variable we'll define next
}
注意这个大括号,js可以在这里面执行并将返回添加到view里。首先我们定义一个列表变量:
const list = props.listItems.map((el, i)=>(
// All where doing here is getting the items listItems prop
// (which is stored in the state of the parent component)
// which is an array, and we're running the .map method
// which returns a new array of list items. The key attribute is
// required, and must be unique.
el
));
完整的组件如下:
import React from 'react';
const List = (props) => {
const list = props.listItems.map((el, i)=>(
this.setState((previousState)=>({
list: [...previousState.list, previousState.newToDo ], // the spread opperator is called by using the ... preceding the array
}));
onListItemClick = (i) => { // takes the index of the element to be updated
this.setState((previousState)=>({
list: [
...previousState.list.slice(0, i), // slice returns a new array without modifying the existing array. Takes everything up to, but not including, the index passed in.
Object.assign({}, previousState.list[i], {done: !previousState.list[i].done}), // Object.assign is a new ES6 feature that creates a new object based on the first param (in this case an empty object). Other objects can be passed in and will be added to the first object without being modified.
...previousState.list.slice(i+1) // takes everything after the index passed in and adds it to the array.
]
}))
};
deleteListItem = (i) => {
this.setState((previousState)=>({ // using previous state again
list: [
...previousState.list.slice(0, i), // again with the slice method
...previousState.list.slice(i+1) // the only diffence here is we're leaving out the clicked element
]
}))
};
const initialState = {}; //The initial state of this reducer (will be combined with the states of other reducers as your app grows)
export default function reducer(state = initialState, action){ // a function that has two parameters, state (which is initialized as our initialState obj), and action, which we'll cover soon.
switch (action.type){
default:
return state;
}
}
4. 完善Store
现在我们已经完成了第一个reducer,可以将其添加到 configureStore.js 中去了, 导入: import toDoApp from './modules/toDoApp';
function mapStateToProps(state) {
return {
toDoApp: state.toDoApp // gives our component access to state through props.toDoApp
}
}
function mapDispatchToProps(dispatch) {
return {}; // here we'll soon be mapping actions to props
}
import { Provider } from 'react-redux';
import ToDoAppContainer from './containers/ToDoAppContainer';
import configureStore from './redux/configureStore';
configureStore is the function we created that takes our combined reducers and our redux middleware and mashes them all together. Let's intialize that with the following line:
function addItem(item){
return {
type: ADD_ITEM,
item // this is new ES6 shorthand for when the key is the same as a variable or perameter within the scope of the object. It's the same as item: item
}
}
Reducers
reducer是唯一可以触碰store的元素,初始值为initialState,形式上就是一个简单的switch语句,但是注意不能直接改变state,因为state是immutable。也就是说我们不能直接使用.pop or .push这些方法操作数组。
下面是示例代码:
const initialState = {
list: []
};
export default function reducer(state = initialState, action){
switch (action.type){
case ADD_ITEM:
return Object.assign(
{},
state,
{ list: [...state.list, action.item]} // here we see object.assign again, and we're returning a new state built from the old state without directly manipulating it
)
default:
return state;
}
}
概念已经介绍完毕,下面开始将原来的功能逻辑用redux重写。
1. Initial state
首先我们在 src/redux/modules/toDoApp中声明initialState。
const initialState = {
list: [{item: 'test', done: false}] // just added this to test that state is being passed down propperly,
newToDo: ''
};
export default function reducer(state = initialState, action){
switch (action.type){
default:
return state;
}
}
import { connect } from 'react-redux';
import ToDoApp from '../components/ToDoApp.js'
import {
inputChange
} from '../redux/modules/toDoApp'; // we added this
function mapStateToProps(state) {
return {
toDoApp: state.toDoApp // gives our component access to state through props.toDoApp
}
}
function mapDispatchToProps(dispatch) {
return {
inputChange: (value) => dispatch(inputChange(value)) // we added this
};
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(ToDoApp);