数据状态交互
简介
对于Vue
有内置的Vuex
来进行数据通信机制,而相对于React
有很多的数据通信机制工具。如flux
这是官方推荐,但是它也有自己的不足,后面有大神(非官方)开发了Redux
,不过也是得到了官方认可和推荐。
为什么会有状态管理
这就要提到React的短板,它也是一个单向数据流,如果想要向父级的父级提交数据,那么就需要父级向下一直传递方法,在当前的组件中调用传递下来的方法,大家可以想像一下,如果有很多级的话该如何做?那么如果还有非父子组件该如何通信? 可以通过全局的订阅和发布来做。
但这并不是最好的解决方案,那么就可以通过我们简介里面的方法去做,在这里,还是需要给大家列举出组件通信的默认方案吧,让大家对其有个更深刻的了解。
孙辈级通信
class Father extends Component {
static childContextTypes = {
color: React.PropTypes.string
};
getChildContext(){
return {
color: 'red'
}
}
constructor (props){
super(props)
}
render (){
return <div>
<Child />
</div>
}
}
class Child extends Component {
static contextTypes = {
color: React.PropTypes.string
}
render (){
const {props} = this
return <div>
<h1 style={{background: this.context.color}}>This is Child.</h1>
</div>
}
}
可以看出,我们在 Father
组件中并未给 Child
组件中进行传 props
,而是在父组件中定义了,childContext
,这样从这一层开始的子组件都可以拿到这个值,需要蓄意的是,使用 context
方式时候,需要写一个 getChildContext
方法来获取这个值。
兄弟或无关组件间通信
没有嵌套关系的,那只能通过影响全局的一些机制去实现。这样看,自定义事件机制不失为一种很好的方案。在这边使用了 EventEmitter
模块(npm
包 node
的基础模块)进行通信。
import React, {Component,PropTypes} from 'react'
import ReactDom from 'react-dom'
import {EventEmitter2} from 'eventemitter2'
var emitter = new EventEmitter2()
class First extends Component {
constructor(props){
super(props)
this.state = {
data: 'init First'
}
emitter.on('changeFirstText', this.changeText.bind(this))
}
changeText( msg ){
this.setState({
data: 'First change success: origin ' + msg
})
}
render (){
return <div>
<h1>{this.state.data}</h1>
</div>
}
}
class Second extends Component {
handleClick(){
emitter.emit('changeFirstText', 'Second')
}
render (){
return <div onClick={ this.handleClick.bind(this) }>
<button>点击修改 First 组件内容</button>
</div>
}
}
在 First
中注册了自定义事件,changeFirstText
,并且绑定好回调函。emitter.on('changeFirstText', this.changeText.bind(this))
在 Second 当用户点击发送信息请求时,在 handleClick
中,触发 changeFirstText
事件,并且把需要的信息传给过去。emitter.emit('changeFirstText', 'Second')
简单学习一下flux(了解即可)
React 标榜自己是 MVC
里面 V
的部分,那么 Flux
就相当于添加 M
和 C
的部分。
Flux 是 Facebook
使用的一套前端应用的架构模式。一个 Flux 应用主要包含四个部分:
-
the dispatcher
处理动作分发,维护 Store 之间的依赖关系
-
the stores
数据和逻辑部分
-
the views
React 组件,这一层可以看作 controller-views,作为视图同时响应用户交互
-
the actions
提供给 dispatcher 传递数据给 store
先来了解一下 Flux 的核心“单向数据流“怎么运作的:
Action -> Dispatcher -> Store -> View
掌握redux
简介
如果说flux
只是一种思想,那么redux
就是对flux的具体实现。我们去学习redux
时不要总着眼于概念,我们可以亲自的先使用一下,再去书写一下它的功能,这样大家对其会有一个更深刻的概念,我希望通过这个课程的讲解,为的就是将来能够面试时有个更好的体验。
使用:
安装
npm install --save redux或yarn add redux
在这期中有四个概念,我们一开始已经有一个状态,也就是我们的view
层,即组件层,我们在一开始,先去实现仓库以及Reducers
使其建立联系。
import { createStore } from 'redux'
function reducer(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}
let store = createStore(reducer)
store.subscribe(() => console.log(store.getState()))
store.dispatch({ type: 'INCREMENT' })
store.dispatch({ type: 'INCREMENT' })
store.dispatch({ type: 'DECREMENT' })
其中reducer函数我对其官网的翻译直接拿过来给大家来看
这是一个reducer,一个带有(state,action)=>状态签名的纯函数。它描述了一个操作如何将状态转换为下一个状态。状态的形状取决于您:它可以是一个原语、一个数组、一个对象,甚至是不可变的.js数据结构。唯一重要的部分是,您不应该改变状态对象,而是在状态改变时返回一个新对象。
在本例中,我们使用“switch”语句和字符串.
对上面的例子,我们当然可以结合 react
的组件进行使用。不过我们还可以进行一个更好的例子,todolist
来实现。
TODOlistui组件
import React, {Component} from 'react';
import 'antd/dist/antd.css'
import * as actions from './Store/actionsCreators'
import store from './Store';
import TodoListUi from './TodoListUi'
import axios from "axios";
import {initListAction} from "./Store/actionsCreators";
//容器组件 是聪明组件,UI组件是傻瓜组件,那么可以使用无状态组件。
export default class TodoList extends Component {
constructor(props) {
super(props);
this.state = store.getState()
this.Hchange = this.Hchange.bind(this)
this.HstoreChange = this.HstoreChange.bind(this)
this.Hremove = this.Hremove.bind(this)
store.subscribe(this.HstoreChange)
}
HstoreChange() {
this.setState(store.getState())
}
Hchange(e) {
actions.getInputChangeAction(e.target.value)
}
Hremove(index) {
actions.deleteTodoItemAction(index)
}
Hadd(e) {
if (e.keyCode !== 13) return;
actions.addTodoItemAction();
}
render() {
return (
<TodoListUi
list={this.state.list}
Hchange={this.Hchange}
Hremove={this.Hremove}
Hadd={this.Hadd}
inputValue={this.state.inputValue}></TodoListUi>
);
}
async componentDidMount() {
let res =await axios.get('http://localhost:3000/json/res.json')
if(!res) return;
initListAction(res.data)
}
}
TodoList组件
import React, {Component} from 'react';
import 'antd/dist/antd.css'
import * as actions from './Store/actionsCreators'
import store from './Store';
import TodoListUi from './TodoListUi'
//容器组件 是聪明组件,UI组件是傻瓜组件,那么可以使用无状态组件。
export default class TodoList extends Component {
constructor(props) {
super(props);
this.state = store.getState()
this.Hchange = this.Hchange.bind(this)
this.HstoreChange = this.HstoreChange.bind(this)
this.Hremove = this.Hremove.bind(this)
store.subscribe(this.HstoreChange)
}
HstoreChange() {
this.setState(store.getState())
}
Hchange(e) {
actions.getInputChangeAction(e.target.value)
}
Hremove(index) {
actions.deleteTodoItemAction(index)
}
Hadd(e) {
if (e.keyCode !== 13) return;
actions.addTodoItemAction();
}
render() {
return (
<TodoListUi
list={this.state.list}
Hchange={this.Hchange}
Hremove={this.Hremove}
Hadd={this.Hadd}
inputValue={this.state.inputValue}></TodoListUi>
);
}
componentDidMount() {
const action = actions.getTodoList();
store.dispatch(action)
}
}
store文件
//1.先创建数据模型
/*
import {createStore} from 'redux';
const store = createStore();
export default store;
*/
// 2.管理员什么都不知道需要我新建一个函数reducer.js 返回一个函数,里面传递参数 state和action
import reducer from './reducer'
import {createStore,applyMiddleware} from 'redux';
import {composeWithDevTools} from 'redux-devtools-extension'
const store = createStore(
reducer,
composeWithDevTools()
);
export default store;
2.reducer文件
//图书管里面有许多的图书和图书的 权限和方法(借阅/镇馆)
import * as types from './actionTypes'
//初始数据模型
const defaultState = {
inputValue:'',
list:[1,2]
}
export default (state=defaultState,action)=>{
if(action.type===types.CHANGE_INPUT_VALUE){
const newstate = JSON.parse(JSON.stringify(state));
newstate.inputValue = action.value;
return newstate; //固定写法reducer可以接受state,但不能修改state
}
if(action.type===types.ADD_TODO_ITEM){
const newstate = JSON.parse(JSON.stringify(state));
newstate.list.push(state.inputValue)
newstate.inputValue = ''
return newstate; //固定写法reducer可以接受state,但不能修改state
}
if(action.type===types.DELETE_TODO_ITEM){
const newstate = JSON.parse(JSON.stringify(state));
newstate.list.splice(action.index,1)
newstate.inputValue = ''
return newstate; //固定写法reducer可以接受state,但不能修改state
}
if(action.type===types.INIT_LIST){
const newstate = JSON.parse(JSON.stringify(state));
newstate.list= action.arr;
return newstate; //固定写法reducer可以接受state,但不能修改state
}
return state;
}
3.actions
import * as types from './actionTypes'
import store from './index';
import axios from "axios";
export const getInputChangeAction=(value)=>{
store.dispatch({
type:types.CHANGE_INPUT_VALUE,
value
})
};
export const addTodoItemAction=()=>{
store.dispatch({
type:types.ADD_TODO_ITEM
})
}
export const deleteTodoItemAction=(index)=> {
store.dispatch({
type:types.DELETE_TODO_ITEM,
index
})
}
export const initListAction=(arr)=> {
store.dispatch({
type:types.INIT_LIST,
arr
})
}
4.antionsTypes
export const CHANGE_INPUT_VALUE='CHANGE_INPUT_VALUE';
export const ADD_TODO_ITEM = 'ADD_TODO_ITEM';
export const DELETE_TODO_ITEM = 'DELETE_TODO_ITEM'
export const INIT_LIST = 'INIT_LIST'
上面案例如能跟上来那么就需要我们对其有个好的了解。接下来我们要实现一个功能即我们要进行手写redux
简单实现即可。
网友评论