Awesome Redux 包含文档,redux项目,以及一些脚手架工具html
reactjs101node
full stack redux tutorialreact
慕课网git
the-soundcloud-client-in-react-reduxgithub
参考资料:npm
观看example的时候,要把整个脉络action--》reducer---》store---》搞清楚,好比reducer要书写,参考(action--》reducer这条线)因此须要action这个参数入侵。好比store要书写,须要reducer--》store,因此须要reducer入侵。redux
代码的编写参考例子。api
有时候cnpm不起做用,多是被360拦截了。
数组
添加信任就能够了。
一个入门demo,描述了redux如何运做的过程,从action--》reducer---》store---》更新应用state的过程。
注意点:redux采用的是消费订阅者模式。
commonjs方式的demo。简易版的demo,方便了解整个rudux过程。
Redux 结合 React 使用的最基本示例。出于简化,当 store 发生变化,React 组件会手动从新渲染。在实际的项目中,可使用 React 和 Redux 已绑定、且更高效的 React Redux。
要点
onIncrement={() => store.dispatch({type:'INCREMENT'})}
关联store,让store去dispatch相应的动做,根据subscribe到store的reducer去判断类型,进行操做。这也是redux的底层的操做。import React,{Component} from 'react' /*class Counter extends Component { }*/ const incrementIfOdd = (value,onIncrement) => { if (value % 2 !== 0) { onIncrement() } } const incrementAsync = (onIncrement) => { setTimeout(onIncrement, 1000) } export default ({value,onIncrement,onDecrement})=>{ return ( <p> Clicked: {value} times <button onClick={onIncrement}> + </button> <button onClick={onDecrement}> - </button> <button onClick={e=>{ incrementIfOdd(value,onIncrement) } }> incrementIfOdd </button> <button onClick={ e=>{ incrementAsync(onIncrement) } }> incrementAsync </button> </p> ) }
注意 onClick里面不能直接{incrementifOdd(value,onIncrement)}
问题:
深刻理解在 Redux 中 state 的更新与组件是如何共同运做的例子。展现了 reducer 如何委派 action 给其它 reducer,也展现了如何使用 React Redux 从展现组件中生成容器组件。
要点
import React from 'react' import { connect } from 'react-redux' import { addTodo } from '../actions' let AddTodo = ({ dispatch }) => { let input return ( <div> <form onSubmit={e => { e.preventDefault() if (!input.value.trim()) { return } dispatch(addTodo(input.value)) input.value = '' }}> <input ref={node => { input = node }} /> <button type="submit"> Add Todo </button> </form> </div> ) } AddTodo = connect()(AddTodo) export default AddTodo
比较这两个写法:具体看api使用:FilterLink.js里的定义是一个函数,VisibleTodoList里的定义是一个对象。
比较FilterLink.js和VisibileTodoList.js的mapDispatchToProps写法,注意二者的区别FilterLink是属性在标签里定义了。因此:
const mapDispatchToProps = (dispatch,ownProps) => ({ onClick:()=>{ dispatch(setVisibilityFilter(ownProps.filter)) } })
而VisibleTodoList的是从内部去跑这个方法的。
const mapDispatchToProps = { onTodoClick: toggleTodo }
另外,参考undo里面有一个写法:这也是传入id来处理的。
const mapDispatchToProps = (dispatch) => { return { onTodoClick: (id) => { dispatch(toggleTodo(id)) } } }
参数传递在Todo里面
const todoList = ({todos,onTodoClick})=>{ return (<ul> {todos.map(todo => <Todo key={todo.id} {...todo} onClick={()=> onTodoClick(todo.id)} /> )} </ul>) }
要点:
import React, { Component, PropTypes } from 'react' import classnames from 'classnames' export default class TodoTextInput extends Component { static propTypes = { onSave: PropTypes.func.isRequired, text: PropTypes.string, placeholder: PropTypes.string, editing: PropTypes.bool, newTodo: PropTypes.bool } state = { text: this.props.text || '' } handleSubmit = e => { const text = e.target.value.trim() if (e.which === 13) { this.props.onSave(text) if (this.props.newTodo) { this.setState({ text: '' }) } } } handleChange = e => { this.setState({ text: e.target.value }) } handleBlur = e => { if (!this.props.newTodo) { this.props.onSave(e.target.value) } } render() { return ( <input className={ classnames({ edit: this.props.editing, 'new-todo': this.props.newTodo })} type="text" placeholder={this.props.placeholder} autoFocus="true" value={this.state.text} onBlur={this.handleBlur} onChange={this.handleChange} onKeyDown={this.handleSubmit} /> ) } }
这种写法,内部保持一个state,须要state通常是须要和用户进行交互,改写onKeyDown源文件以下函数组件:
import React from 'react' import classnames from 'classnames' /*const handleSubmit =(e)=>{ const text = e.target.value.trim() if(e.which === 13) { } } const handleBlur = (e)=>{ console.log(this.props) }*/ const TodoTextInput =({...props})=> <input type="text" className={ classnames({ edit: props.editing, 'new-todo': props.newTodo })} autoFocus="true" /* onBlur={handleBlur}*/ onKeyDown={(e)=>{ const text = e.target.value.trim() if(e.which === 13&&text!=='') { props.onSave(text) e.target.value="" } }} placeholder={props.placeholder}/> export default TodoTextInput
注意这里onKeyDown里面要引用外部的props,因此不能抽取到外面handleSubmit方法。会报props找不到。换个思路,若是使用连接工厂的方式:
onBlur={handleBlur(props)} ----------------------------------------------------- const handleBlur = (props)=>(e)=>{ //连接工厂的方式 console.log(props,e,e.target.value) }
这样也是能够的。或者换个思路
onBlur={e=>{handleBlur(props,e)}} ----------------------------------------- const handleBlur = (props,e)=>{ console.log(props,e,e.target.value) }
函数调用。通常下面的方法,若是只写一个textxxx那么textxxx均可以调用的到,若是这样写了,根据就近原则,内部函数先调用了。
import React from 'react' import TodoTextInput from './TodoTextInput' const textsss = ()=>{ console.log("xx") } const Header = ({addTodo}) => { const textsss = ()=>{ console.log("xxwww") } //这里如何定义内部方法。 return (<header className="header"> <h1>todos</h1> <TodoTextInput newTodo onSave={(text)=>{ textsss() addTodo(text) }} placeholder="what need to be done?" /> </header>) } export default Header
const TODO_FILTERS = { [SHOW_ALL]: () => true, [SHOW_ACTIVE]: todo => !todo.completed, [SHOW_COMPLETED]: todo => todo.completed }
这里[]:xxx,[]里面的是一个变量。
reduces/todos.js 里面的complete里面的一个写法:对象扩展运算符,...todo,就是把对象扩展了。而后后面的属性覆盖前面的。
case types.COMPLETE_TODO: return state.map(todo=>{ return todo.id === action.id? {...todo,completed:!todo.completed}: todo })
能够参考这篇文章。
export const fetchPostsIfNeeded = reddit => (dispatch, getState) => { debugger if (shouldFetchPosts(getState(), reddit)) { return dispatch(fetchPosts(reddit)) } }
这里getState是从哪里注入进来的?注意这里调用方是
componentDidMount() { const { dispatch, selectedReddit } = this.props dispatch(fetchPostsIfNeeded(selectedReddit)) }
dispatch(fetchPostsIfNeeded(selectedReddit))
就是说只有注入dispatch,触发dispatch,才有getState()这个变量。让咱们能够作下一步的操做。能够换成下面的代码块。
export const fetchPostsIfNeeded = reddit =>{ return (dispatch, getState) => { if (shouldFetchPosts(getState(), reddit)) { return dispatch(fetchPosts(reddit)) } } }
dispatch(fetchPostsIfNeeded(selectedReddit))
调用的时候,最后返回的是一个函数。能够有这两个变量。咱们修改todomvc 例子里面的action/index.js,加入dispatch,getState(),以下,注意,若是想改为这样的话,
export const addTodo = text =>(dispatch,getState)=> {debugger;return ({ type: types.ADD_TODO, text })}
必须加入中间件。发现这是系统调用的时候调用的时候自动加入的。这也能够理解,actioncreator原本是要返回一个plain的obj,不过如今须要作其余的操做(网络请求),就须要中间件。按照正常的逻辑,走网络请求获得数据应该要走网络请求,因此函数的参数,就是状态(getState)和动做(dispatch)。继续作下一步的处理
使用thunk中间件是由于actionCreator不只仅要返回一个plain对象,还要在函数里面作一些操做。好比异步请求,而后最后返回的是一个函数。
当 action creator 返回函数时,这个函数会被 Redux Thunk middleware 执行。这个函数并不须要保持纯净;它还能够带有反作用,包括执行异步 API 请求。这个函数还能够 dispatch action,就像 dispatch 前面定义的同步 action 同样。
比较这两种写法:
productContainer
<ProductsList title="Products"> {products.map(product => <ProductItem key={product.id} product={product} onAddToCartClicked={() => addToCart(product.id)} /> )} </ProductsList>
productItem里面:
<button onClick={onAddToCartClicked} disabled={product.inventory > 0 ? '' : 'disabled'}> {product.inventory > 0 ? 'Add to cart' : 'Sold Out'} </button>
这种写法把点击事件的具体操做放到外层容器处理。
另外一种写法是:
productContainer
<ProductsList title={"shoppingcart"}> {products.map(product=><ProductItem key={product.id} product={product} addToCart={addToCart}/>)} </ProductsList>
productItem里面作处理:
export default ({product,addToCart}) => ( <div> <Product title={product.title} price={product.price} /> <button onClick={()=>addToCart(product.id)} disabled={product.inventory > 0 ? '' : 'disabled'}> {product.inventory > 0 ? 'Add to cart' : 'Sold Out'} </button> </div>)
在productItem里面onClick另外处理,处理的场景不同而已。主要是看业务须要分割到什么样的程度。
注意如下这两种写法:
actions.js
export const testConsoleProductUnderirect = ()=>dispatch=>{ dispatch({ type:types.TEST_CONSOLE_PRODUCTS }) } export const testConsoleProductInderirect = ()=>({ type:types.TEST_CONSOLE_PRODUCTS })
调用方式为
store.dispatch(testConsoleProductUnderirect())
store.dispatch(testConsoleProductInderirect())
第二种是常规的写法,就是返回一个普通的action对象。第一种写法是要由thunk中间件来触发的写法。注意
const xx=()=>dispatch=>({XX:XX})
每一层 箭头都是有()包裹,是直接返回的。第一个xx=()=>dispatch
说明是返回一个参数为dispatch的函数,通常actionCreator是要返回action对象的,这里返回了一个函数,须要用到thunk支持,第二层箭头>dispatch=>{ dispatch({ type:types.TEST_CONSOLE_PRODUCTS }) }
里面就能够dispatch其余操做。根据中间件文档的解释,中间件处理过程以下。传入action,而后返回next----》dispatch这个action,而后再store
这个next
store => next => action
层层嵌套。
注意使用了中间件以后,第二种actionCreator能够返回任意东西。只要有dispatch参数进去就能够了。
export const testConsoleProductUnderirect = ()=>dispatch=>{ console.log("hello kitty") /*dispatch({ type:types.TEST_CONSOLE_PRODUCTS })*/ }
第一种同步actionCreator不行
export const testConsoleProductInderirect = ()=>{ console.log("hello kitty") }
这样写是会报错的。