摘要:上一篇也许是最佳小实践加入在组件之间流通数据更确切的说,这被叫做单向数据流数据沿着一个方向从父组件流到子组件。这个将这个新的对象附加到上,并将它返回,用来更新。这一次,将当前的状态仍旧是空数组和对象一起传递给了。
上一篇:react、react-router、redux 也许是最佳小实践1
加入 reduxReact 在组件之间流通数据.更确切的说,这被叫做“单向数据流”——数据沿着一个方向从父组件流到子组件。由于这个特性,对于没有父子关系的两个组件之间的数据交流就变得不是那么显而易见。这里 Redux 就排上用场了。Redux提供了一个解决方案,通过将应用程序所有的状态都存储在一个地方,叫做“store”。然后组件就可以“dispatch”状态的改变给这个store,而不是直接跟另外的组件交流。所有的组件都应该意识到状态的改变可以“subscribe”给store。如下图:
原理讲完,下面开始加入代码。
先看看一个小例子。
开始之前,需要先用 Redux.createStore() 创建一个store,然后将所有的reducer作为参数传递进去,让我们看一下这个只传递了一个reducer的小例子:
var userReducer = function(state, action) { if (state === undefined) { state = []; } if (action.type === "ADD_USER") { state.push(action.user); } return state; } var store = Redux.createStore(userReducer); store.dispatch({ type: "ADD_USER", user: {name: "xiaoming"} });
上面的程序干了些什么呢:
这个store只由一个reducer创建。
这个reducer 初始化状态的时候使用了一个空数组 。*
在被分派的这个action里面使用了新的user对象。
这个reducer将这个新的user对象附加到state上,并将它返回,用来更新store。
*在这个例子里reducer实际上被调用了两次 —— 一次是在创建store的时候,一次是在分派action之后。
当store被创建之后,Redux立即调用了所有的reducer,并且将它们的返回值作为初始状态。第一次调用reducer传递了一个 undefined 给state。经过reducer内部的代码处理之后返回了一个空数组给这个store的state作为开始。
所有的reducer在每次action被分派之后都会被调用。因为reducer返回的状态将会成为新的状态存储在store中,所以 Redux总是希望所有的reducer都要返回一个状态。
在这个例子中,reducer第二次的调用发生在分派之后。记住,一个被分派的action描述了一个改变状态的意图,而且通常携带有数据用来更新状态。这一次,Redux将当前的状态(仍旧是空数组)和action对象一起传递给了reducer。这个action对象,现在有了一个值为1ADD_USER的type属性, 让reducer知道怎样改变状态。
正式redux登场在 src 下面创建一个 redux、actions、 data(存放一些初始数据)文件夹,然后在 data文件夹下面创建一个db.js,这个文件写上一些初始的数据:
src/data/db.js
const data = [ { id: 1, title: "明天要去打酱油", content: "系呀系呀我们一起打酱油" }, { id: 2, title: "周末去书吧读书", content: "书籍是人类进步的阶梯" }, { id: 3, title: "备份一下数据库", content: "备份服务器的数据库,一般都是分开的,分布式数据库" }, { id: 4, title: "周五记得把被子洗了", content: "洗杯子被子被子被子" }, { id: 5, title: "计划五", content: "计划五内容" } ] export default data
好了,初始的数据我们有了,下面就是创建 store 了,在redux文件夹下面,创建一个planlist.js文件,这个文件就是操作 store 的动作 action集合处理的数据,这时候我们会去action文件夹下面新建,action-type.js 和plan.js,代码如下:
src/action/action-type.js
export const ADD = "ADD"; export const DELECT = "DELECT"; export const SHOW = "SHOW";
src/action/plan.js
import * as types from "./action-type.js"; // 添加计划 export function addPlan(item) { return { type: types.ADD, item }; } // 删除计划 export function deletePlan(id) { return { type: types.DELECT, id }; } // 显示隐藏弹层 export function show(show) { return { type: types.SHOW, show }; }
action 我们都定义好了现在我们就可以改变 store了。写好我们的 reducer
src/redux/planlist.js
import * as types from "../actions/action-type.js"; import data from "../data/db.js" const initialState = { show: false, // 是否显示弹出 planlist: data // 初始的计划表 }; const planReducer = function(state = initialState, action) { let list = state.planlist; switch(action.type) { // 添加计划 case types.ADD: list.push(action.item); return Object.assign({}, state, { planlist: list }); // 删除计划 case types.DELECT: let newstate = list.filter((item) => item.id != action.id); return Object.assign({}, state, { planlist: newstate });; // 显示、隐藏弹出层 case types.SHOW: return Object.assign({}, state, { show: action.show }); } return state; } export default planReducer;
在redux 下面再创建reducers.js和store.js,
src/redux/reducers.js
import { combineReducers } from "redux"; // Reducers import planlist from "./planlist"; // Combine Reducers var reducers = combineReducers({ planlist: planlist }); export default reducers;
src/redux/store.js
import { createStore } from "redux"; import reducers from "./reducers.js"; const store = createStore(reducers); export default store;
这会我们的 store 就完全的创建好了,下面就是把 store 跟我们的组件,完全的结合起来。这就用到 react-redux 的 connect 模块。
这个东西 就是把组件跟 store 连接起来的模块。
然后在,App.js加入我们的。store
src/App.js
import React, { Component } from "react" import { BrowserRouter as Router, Route, Link } from "react-router-dom" // 引入 store import { Provider, connect } from "react-redux"; import store from "./redux/store.js" import logo from "./logo.svg" import Plan from "./components/plan.js" import Home from "./components/home.js" import Popup from "./components/pupop.js" import TestRouter from "./components/testrouter.js" import Detail from "./components/detail.js" import "./App.css" import "./components/comment.css" import createHistory from "history/createBrowserHistory" const history = createHistory() class App extends Component { constructor(props) { super(props); } render() { return ( // store的挂载); } } export default App Welcome to React Plan
- 首页
- 计划表
- 二级路由
然后在 plan.js连接 store
src/component/plant.js
import React, { Component } from "react" import { connect } from "react-redux"; import store from "../redux/store.js"; // 引入 定义的 action import {show, deletePlan} from "../actions/plan.js"; class Plan extends Component { constructor(props) { super(props); } // 显示弹出 show () { let b = this.props.planlist.show; store.dispatch(show(!b)); } // 删除计划 delete (id) { store.dispatch(deletePlan(id)); } // js 跳转路由 detail (id) { this.props.history.push(`/detail/${id}`) } render () { return () } } const mapStateToProps = function(store) { return { planlist: store.planlist }; }; // 连接 store,作为 props export default connect(mapStateToProps)(Plan);计划表
添加计划
{ this.props.planlist.planlist.map((item, index) => { return ( 标题 操作 ) }) } {item.title} 删除
同理下面的 js,都是用这个模块连接
src/component/detail.js
import React, { Component } from "react" import { connect } from "react-redux"; import store from "../redux/store.js"; class Detail extends Component { constructor(props) { super(props); // 根据路由 id 跟 store 做过滤 let item = props.planlist.planlist.filter((data) => data.id == props.match.params.id) console.log(item) this.state = { plan: item[0] } } render() { return () } } const mapStateToProps = function(store) { return { planlist: store.planlist }; }; // 连接 tore 和组件 export default connect(mapStateToProps)(Detail);计划详情
id: {this.state.plan.id}
标题: {this.state.plan.title}
内容: {this.state.plan.content}
src/component/popup.js
import React, { Component } from "react" import { connect } from "react-redux"; import store from "../redux/store.js"; import {show, addPlan} from "../actions/plan.js"; class Pupop extends Component{ constructor (props) { super(props) this.state = { id: "", title: "1", content: "1" } } // 取消按钮操作 close () { let b = this.props.planlist.show; this.setState({ id: "", title: "", content: "" }) store.dispatch(show(!b)); } // 输入框事件 handleChage (str, e) { this.setState({ id: Math.ceil(Math.random()*10000), [str]: e.target.value }) } // 确认操作 conform () { store.dispatch(addPlan(this.state)); this.setState({ id: "", title: "", content: "" }) this.close(); } render() { let self = this; return () } } const mapStateToProps = function(store) { return { planlist: store.planlist }; }; // 连接 store和组件 export default connect(mapStateToProps)(Pupop); X计划标题
计划内容
取消 确认
完工。github地址
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/83408.html
摘要:通过声明式编程模型定义组件,是最强大的核心功能。无论是的浏览器书签,还是的导航功能,只要是可以使用的地方,就可以使用。二级路由使用渲染组件属性状态请选择一个主题。也许是最佳小实践地址,觉得有帮助的话,请点击一下,嘿嘿 小前言 这是一个小小的有关react的小例子,希望通过一个小例子,可以让新手更好的了解到react、react-router4.0、redux的集中使用方法。 这是基...
摘要:译者按最近依旧如火如荼相信大家都跃跃欲试我们团队也开始在领域有所尝试年应该是逐渐走向成熟的一年让我们一起来看看国外的开发者们都总结了哪些最佳实践年在全世界都有很多关于新的更新和开发者大会的讨论关于去年的重要事件请参考那么年最有趣的问题来了我 译者按:最近React(web/native)依旧如火如荼,相信大家都跃跃欲试,我们团队也开始在React领域有所尝试. 2016年应该是Reac...
摘要:首先声明这篇文章是想说明一下最新版本的的新特性带来的极大的开发体验提升而不是如何利用开发应用这个特性就是对的支持在的中有说明具体可以参考这里在版本之前我们在开发应用尤其是在配合一类库的时候经常用到诸如之类的封装而这些函数其实都可以用装饰器的 首先声明, 这篇文章是想说明一下最新版本的 TypeScript(3.0) 的新特性带来的极大的 React 开发体验提升. 而不是如何利用 Ty...
阅读 1337·2021-11-15 11:45
阅读 3109·2021-09-27 13:36
阅读 2825·2019-08-30 15:54
阅读 971·2019-08-29 12:38
阅读 2884·2019-08-29 11:22
阅读 2971·2019-08-26 13:52
阅读 2003·2019-08-26 13:30
阅读 538·2019-08-26 10:37