Redux

Redux 基础


http://cn.redux.js.org/


安装
  1. npx create-react-app:安装 react
  2. yarn add redux:生产环境安装
  3. 部分使用:项目部分数据使用 redux 管理。全局使用:项目中所有数据全使用 redux 管理。项目一旦使用 redux 就说明项目数据量一定是大的,推荐全局使用
  4. 注意 React 层获取 state 不是 state.js 内,而是通过订阅-发布从 store 获取,而 store的 state 值是 reducer 提供的

流程图


手动撸一个输入添加到列表的东西

目录结构:

src
	store
		index.js			  	创建 store 对象
		actionCreator.js		动作创建者
		reducer.js    			函数,通过动作设置 state
		state.js				state 设定初始值
		type.js					这就是来搞笑的(高大上的)
	page
		todos
			index.css			设置样式
			index.js			对 todos 所有组件一起导出
			TodosContent.js 	组件
			TodosInput.js		组件
1. store/index.js:创建 store 实例
1.从redux模块结构出 createStore 用于创建 store 实例
import { createStore } from 'redux'    
import reducer from './reducer'

2.这里接受一个函数做参数,需要打造 reducer 函数
const store = new createStore( reducer )	
export default store

实例出来的store 对象有 dispatch 和 getState方法。区别 flux

dispatch: ƒ dispatch(action)
getState: ƒ getState()
replaceReducer: ƒ replaceReducer(nextReducer)
subscribe: ƒ subscribe(listener)
Symbol(observable): ƒ observable()


2. store/state.js:设置 state 初始值
const state = {
  todos:[
    {id:1,text:'学习'},
    {id:2,text:'LOL'}
  ]
}
export default state

3. store/reducer.js:纯函数,根据动作改变 state
这里reducer是一个纯函数,接受两个参数。第一个参数是之前的状态,一个是aciton
reducer 函数的返回值是什么,store 的初始值就是什么

import state from './state'
import * as type from './type'

const reducer = (previousState = state, action) => {    这里给previousStare传默认值
  var newState = {
    ...previousState	老师说这是深拷贝,避免直接对 state 操作
  }
  
  switch (action.type) {	通过对 action.type 判断,对 state 做不同处理
    case type.INCREMENT:
      newState.todos.push({
        id: newState.todos.length + 1,
        text: action.payload
      });
      break;
    default: break;
  }

  return newState	返回给 state
}

export default reducer

4. store/actionCreator.js:创造 aciton 对象,提交给 reducer
import * as type from './type'
import store from '.';

const actionCreator ={
  addTodos(val) {
    let action = {
      type: type.INCREMENT,
      payload: val
    }
    
    store.dispatch( action,val )
    
    这里的 dispatch 由 store提供,区别 flux 手动打造
    store.dispatch( action,val )等同于将 payload 写在 action 内
    /* 
    let action ={
      type:type.ADD_TODOS,
      payload:val
    }
    */    
  }
}

export default actionCreator

5. store/type.js
export const INCREMENT = 'INCREMENT'

1. page/todos/TodoInput.js
import React from 'react'
import actionCreator from '../../store/actionCreator'

class TodosInput extends React.Component {
  add = e => {    添加onkeyup的事件处理程序
    if (e.keyCode === 13) {    判断 keyCode 确定回车键
      actionCreator.increment(this.refs.todos_input.value)    触发 actionCreator
      this.refs.todos_input.value = ''    清空输入框
    }
  }

  render() {
    return (
      <div className="TodosContent">
        <input
          type="text"
          placeholder="请输入待办事项"
          
          通过 ref 绑定 DOM,这里 ref 也可以接受一个回调函数 
          // ref={ el => this.todosinput = el }
          ref='todos_input'
          
          onKeyUp={this.add}    绑定事件
        />
      </div>
    )
  }
}

export default TodosInput

2. page/todos/TodoInput.js
import React from 'react'
import store from '../../store'

function Item(props) {    创建 Item 无状态组件
  return (
    <li>{props.item.text}</li>    通过 props 设置 li 标签内容
  )
}

class TodosContent extends React.Component {
  constructor() {
    super()
    this.state = {
      todos: store.getState().todos    通过 store.getState() 获取 state 值
    }
  }

  renderItem = () => {    设置一个方法,返回一个结构
    return this.state.todos.map(item => {    遍历状态 获取结构,
      return (
        <Item item={item} key={item.id} />    使用无状态组件,分离结构和逻辑,这里直接写<li></li>也是可以
      )
    })
  }

  render() {
    return (
      <div className="TodosContent">
        {this.renderItem()}    调用方法获取结构
      </div>
    )
  }

  componentWillMount() {    通过钩子订阅事件
  
    store.subscribe(() => {   事件订阅,当 state 改变,需要用这个更新状态
     
    状态不会自动更新,上边 constructor 内 this 是写死的。
    需要重新对状态修改,状态的修改不能直接赋值,需要 this.setState() 方法,接受一个对象即新状态
      this.setState({
        todos: store.getState().todos
      })
    })
  }
}
export default TodosContent

3. page/todos/index.js
import TodosContent from './TodosContent'
import TodosInput from './TodosInput'
import './index.css'

export { TodosContent, TodosInput }


Redux 进阶

1. combineReducers 数据模块划分

Redux 数据模块划分
在实际中,我们对数据分块。一个项目中存在很多数据,我们不能都放在 state 中,这样导致混乱。我们将整个数据划分,通过中间件我们可以统一管理不同的 reducer 。因为reducer 是真正管理数据的地方。

store目录结构

store
	home
		// index.js    不需要 indexed.js 只需要一个总体的 store 
		type.js
		state.js
		reducer.js
		acttionCreators.js
		
	todos
		type.js
		state.js
		reducer.js
		acttionCreators.js
		
	mine
	...
	index.js
	//state.js	不需要总体的 state 分片自己的 state 
	reducer.js
	
		import { combineReducers } from 'redux'
		import home from './home/reducer'
		const reducer = combineReducers({ home })
		export default reducer
		
	acttionCreators.js

2. react-redux

代码重复问题:
组件内定义状态
事件订阅
actionCreator的action发送

  1. 依赖:yarn add redux
  2. 安装:yarn add react-redux
  3. 在根组件最外层嵌套 Provider 组件,并绑定 store 属性
  4. 在组件内利用 connect 方法使用 store 相关 api(组件内直接通过 props 获取 state)
  5. 作用:简化操作流程,相当于 vuex 的 map 什么鬼,忘了

在使用 redux 中,我们发现有几个动作老师重复的,组件想使用 store 数据,必须在constructor 中利用 store.getState() 获取在挂载在自己状态上。我们要通过 actionCreator 中请求数据,然后发送给前台。
组件想要更新状态需要在 componentWillMount(){} 钩子中利用 store.subscribe() 方法注册一个监听函数,然后获取最新状态后再使用 this.setState() 方法更新自己的状态。如此繁琐的步骤我选择放弃~~
我们引入 react-redux 工具来处理这些问题

react-redux 只是一个辅助工具,将 react 和redux 更好的连接。如果一个组件想要使用 store 中的数据或者 actionCreator 的方法,我们都应该其变化为容器组件包裹 UI 组件的样子。其中,容器组件负责拦截 store,将状态、方法通过 Context 传递给 UI 组件,UI 组件从属性上获取 state 和 actionCreator 方法,并且将事件的订阅自动完成。这就是 react-redux 的核心功能。

核心API
Provider:传递数据
connect:生成容器组件

容器组件、UI 组件
展示组件容器组件
作用描述如何展示(骨架、样式)描述如何运行(数据获取,状态更新)
直接使用Redux
数据来源props监听 Redux state
数据修改从 props调用回调函数向Redux 派发 action
调用方式手动 根据connet生成ui组件由 React Redux 自动生成
Providerconnect

1.代码重复
组件内状态获取
事件订阅
action发送
解决:使用
2.异步
如果异步,则上述解决办法失效,还用重新写
解决:使用中间件

使用

src/index.js

react-redux 帮我们 获取 store 并且帮我们订阅(响应式)

import store from './store'
import { Provider } from 'react-redux'

ReactDOM.render(
  <Provider store={store}>    	包裹根组件,传递 store
    <App />
  </Provider>
  , document.getElementById('root'));

组件.js

import React from 'react'

import { connect } from 'react-redux'
import { bindActionCreators } from 'redux';
import actionCreator from '../../store/actionCreator'

class Mine extends React.Component{
  add=()=>{
    actionCreator.add()
  }
  render(){
    console.log(this.props.dispatch)
    return (
      <div>
        <h3>Mine</h3>
        <p> count:{this.props.count} </p>
        <button onClick={this.add}>+</button>
        <p> name:{this.props.name} </p>
      </div>
    )
  }
}

监听 Redux store 的变化。只要 Redux store 发生改变,mapStateToProps 函数就会被调用。
该回调函数必须返回一个纯对象,这个对象会与组件的 props 合并。

const mapStateToProps = (state)=>{

  如果 state 只有一层,数据直接在 state 内
  return state
  
  如果数据有两次:state={ mine:{name:'zhangsan',count:1} }
  return {
    mine:{...state.mine}
  }
}

将一些能用到 dispatch 的组件传递过去,并且发送动作由这里完成
const mapDispatchToProps = (dispatch)=>{
  return bindActionCreators(actionCreator,dispatch)
}

export default connect(mapStateToProps,mapDispatchToProps)(Mine)

精简版本:!!!!!!!!!!!!!老师说还可以精简,每个组件都要写很烦
export default connect(
  state => ({ mine: { ...state.mine } }),
  dispatch => bindActionCreators(actionCreator, dispatch)
)(Mine)

最终精简版:封装函数

import { connect } from 'react-redux'
import { bindActionCreators } from 'redux';
import actionCreator from 'tore/home/actionCreator'

const getStore = ()=>{
  connect(
    state=>state.home,
    dispatch => bindActionCreators(actionCreator, dispatch)
  )
}
export default getStore 


actionCreator.js

const actionCreator ={

1.这么写
  increment(){
    let action = {
      type:'INCREMENT'
    }
    return action
  }
  
2.或者直接这么写也可以
  increment(val){
 	return {
	 type:type.INCREMENT,
	 payload:val
	}
  }
  
}
 
export default actionCreator

3. redux-thunk 异步请求

在使用 react-redux 中,我们如果在 actionCreator 异步获取数据,会发现 react-redux 失效,只能按照原生 redux 操作。为了解决这个问题,我们使用 redux-thunk 中间件

  1. 安装 yarn add redux-thunk
  2. 创建 store 时使用中间件

当我们使用 react-redux 时候,在actionCreator 中请求数据要进行异步处理,直接在 .then 方法中 return 出 aciton 会报错:Use custom middleware for async actions。如果必须异步请求那么我们不能直接使用 react-redux 工具,还是需要手动写 redux 逻辑。为了解决这个问题,我们使用 redux-thunk 中间件。
action 只是一个对象,不被期望包含异步操作,存在难以维护,业务逻辑不清晰。
使用中间件后,可以解决上述问题,常见的 actionCreator 异步库:

Redux-thunk(主流)
Redux-saga
Redux-effects
Redux-loop

基于 promise 的异步库:
Redux-promise
Redux-promises


如果不使用 redux-thunk,异步获取数据会是下面这样的

actionCreatore.js

import store from "../";

const actionCreator = {
  getName() {
    fetch('/data.json')
      .then(res => res.json())
      .then(data => {
        let action = {
          type: 'GETNAME',
          payload: data
        }
        store.dispatch(action)
      })
      .catch(err => console.log(err))
  }
}
export default actionCreator

组件.js

import React from 'react'
import actionCreator from '../../store/home/actionCreator'
import store from '../../store'

class Name extends React.Component{
  constructor(){
    super()
    this.state={
      name:''
    }
  }
  
  1.这里是老师上课讲的关于异步获取步骤,我觉得不行
  async componentDidMount(){
  	这里调用动作发送请求获取和修改数据,异步
    await actionCreator.getName()
    这里订阅获取数据
    store.subscribe(()=>{
      这里对自己的状态修改,同步。所以要等异步处理完成后在修改自身状态
      this.setState({
        name:store.getState().home.name
      })
    })
  }
  
  2.这是我自己测试的,测试成功。不需要 asyncawait 本身事件订阅接受的就是个回调函数
  在组件挂在前发送数据,然后订阅更新视图
  componentDidMount(){
    actionCreator.getName()
    store.subscribe(()=>{
      this.setState({
        name:store.getState().home.name
      })
    })
  }

  render(){
    return(
      <div>
        <h1> redux 异步请求 </h1>
        <button>获取</button>
        <p>Name:{this.state.name.name}</p>
      </div>
    )
  }
}

export default Name

使用 redux-thunk 中间件

index.js 创建store时候

import {createStore, applyMiddleware } from 'redux'

import thunk from 'redux-thunk'

import reducer from './reducer'

const store = new createStore( reducer, applyMiddleware(thunk) )

export default store

异步请求需要 actionCreator 方法内 return 出一个 dispatch 做参数的箭头函数,函数内调用 dispatch,将创建好的 action 发送给 reducer
actionCreator.js

const actionCreator = {
  getName() {
    return dispatch => {
      fetch('/data.json')    // 在 public 下的直接 /
        .then( res => res.json() )
        .then( res => {
          let aciton = {
            type: type.GETBANNER,
            payload: data
          }
          dispatch(aciton)
        })
        .catch(err => console.log(err))
    }
  }
}

export default actionCreator

组件.js

import React from 'react'

import { connect } from 'react-redux'
import { bindActionCreators } from 'redux';
import actionCreator from '../../store/actionCreator'

class Mine extends React.Component {
  get=()=>{
    this.props.getName()
  }
  render() {
    return (
      <div>
      	注意下边这个写法,相当于三目运算符。目的在于避免第一次渲染时候没有获取到数据而报错
        通过短路运算符判断,有才渲染,没有就不渲染。这个写法在工作中很常见。
        注意:在工作中很少用三院运算符,条件判断和语句判断的层次不是一个级别的。
        推荐使用短路运算符
        <p> name : { this.props.mine && this.props.mine.name } </p>
        <button onClick={this.get}>getName</button>
      </div>
    )
  }
}

export default connect(
  state => ({ mine: { ...state.mine } }),
  dispatch => bindActionCreators(actionCreator, dispatch)
)(Mine)

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于LSTM的财务因子预测选股模型LSTM (Long Short-Term Memory) 是一种特殊的循环神经网络(RNN)架构,用于处理具有长期依赖关系的序列数据。传统的RNN在处理长序列时往往会遇到梯度消失或梯度爆炸的问题,导致无法有效地捕捉长期依赖。LSTM通过引入门控机制(Gating Mechanism)和记忆单元(Memory Cell)来克服这些问题。 以下是LSTM的基本结构和主要组件: 记忆单元(Memory Cell):记忆单元是LSTM的核心,用于存储长期信息。它像一个传送带一样,在整个链上运行,只有一些小的线性交互。信息很容易地在其上保持不变。 输入门(Input Gate):输入门决定了哪些新的信息会被加入到记忆单元中。它由当前时刻的输入和上一时刻的隐藏状态共同决定。 遗忘门(Forget Gate):遗忘门决定了哪些信息会从记忆单元中被丢弃或遗忘。它也由当前时刻的输入和上一时刻的隐藏状态共同决定。 输出门(Output Gate):输出门决定了哪些信息会从记忆单元中输出到当前时刻的隐藏状态中。同样地,它也由当前时刻的输入和上一时刻的隐藏状态共同决定。 LSTM的计算过程可以大致描述为: 通过遗忘门决定从记忆单元中丢弃哪些信息。 通过输入门决定哪些新的信息会被加入到记忆单元中。 更新记忆单元的状态。 通过输出门决定哪些信息会从记忆单元中输出到当前时刻的隐藏状态中。 由于LSTM能够有效地处理长期依赖关系,它在许多序列建模任务中都取得了很好的效果,如语音识别、文本生成、机器翻译、时序预测等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值