Redux 添加数据请求最后渲染
仓库代码:https://gitee.com/zhouyunfang/react-redux.git
目录结构:
1. postForm.js 为提交数据页面
触发action事件方法为 this.props.createPost(post)
import React, { Component } from 'react'
class PostFrom extends Component {
constructor(props) {
super(props)
this.state = {
title: '',
body: ''
};
// this.onChange = this.onChange.bind(this)
}
onChange(e) {//把当前修改的值赋入state
this.setState({
[e.target.name]:e.target.value
})
}
onSubmit(e) {
// 阻止事件传递
e.preventDefault();
// 把表单用的最终数据从state中提取出来,传入请求
const post ={
title:this.state.title,
body:this.state.body
}
// 触发redux 中的action方法,把需要提交的post参数传入
this.props.createPost(post)//把以下原本在页面的fetch请求剪切至actions文件中的PostActions.js文件中
// fetch('http://jsonplaceholder.typicode.com/posts',{
// // post提交
// method:"POST",
// headers:{
// "Content-type":"application/json"
// },
// body:JSON.stringify(post)//把提交的内容转字符串
// })
// .then(res =>res.json())
// .then(data =>{
// console.log(data)
// })
}
render() {
return (
<div>
<h1>添加内容</h1>
<form onSubmit={this.onSubmit.bind(this)}>
<div>
<label >title</label>
<br />
<input type="text" name="title" onChange={this.onChange.bind(this)} defaultValue={this.state.title} />
</div>
<div>
<label >body</label>
<br />
<textarea name="body" id="" cols="30" rows="10" onChange={this.onChange.bind(this)} defaultValue={this.state.body}></textarea>
</div>
<br />
<button type="submit">添加</button>
</form>
</div>
)
}
}
export default PostFrom;
2. postActions.js
(在actions文件下的postActions.js中写入请求,请求成功后由dispatch进行分发,会分发至reducers文件中的
PostReducer.js文件中.
// 引入types.js文件
import { NEW_POST } from './types'
export const createPost = postData => dispatch => {//接收postFrom.js页面传过来的post参数这里形参为postData
fetch('http://jsonplaceholder.typicode.com/posts', {
// post提交
method: "POST",
headers: {
"Content-type": "application/json"
},
body: JSON.stringify(postData)//把提交的内容转字符串
})
.then(res => res.json())
.then(data => {
dispatch({
/**
* type是指定一定要有的,在这里定义的属性值,我们会把它抽离到types.js中
* NEW_POST是dispatch到我们的store中去store会返回到reducer当中,reducer要知道他是哪一个,返回哪一个状态
* 如果dispatch成功会返回到postReducer.js中去,在postreducer.js中去判断type属性值
* */
type: NEW_POST,
// 把请求的data返回回去
payload: data
})
})
}
3. PostReducer.js
(在PostReducer.js文件中对action下的type类型进行判断,判断之后把最新的修改数据 赋值并return出去,会return到reducers文件夹下的index.js中
// 引入 dispatch的type类型
import { NEW_POST } from '../actions/types'
// reducer的作用: 返回新的状态
// 定义一个变量,
const initialState = {
//存储你想要获取的状态
item: []//1.访问到当前的文件中的时候定义一个初始状态
}
export default function (state = initialState, action) {//reducer 就是一个纯函数,接收旧的 state 和 action,返回新的 state。
switch (action.type) {//2.在switch的时候会传过来对应的数据,在此修改状态,返回给到初始定义的属性中最终返回到组件中去
// 对用户添加数据的type类型进行判断
case NEW_POST:
return {
...state,
// 把postActions.js中分发成功的值赋给item
item: action.payload
}
default:
return state;
}
}
4..reducers文件夹下的index.js
(之后会返回到posts.js组件中去最终渲染)
// reducer合成,redux自身提供的一个方法
import { combineReducers } from 'redux'
import postReducer from './PostReducer'
export default combineReducers({
// 这里写生成状态的方法,这个方法会最后合成一个大的reducer,会拆分多个小的
posts:postReducer,//这里是引的posts.js中的state数据
})
5. PostForm.js
在PostForm.js中引入PropType 规定方法和状态的使用类型,connect来连接createPost中的数据.
import React, { Component } from 'react'
// 给不前的状态规定一个数据类型,这是react给我们的一个标准
import propTypes from 'prop-types'
//1. 想让Posts使用fetchPost的方法 ,就要使用reducer中提供的connect来连接
import { connect } from 'react-redux'
// { createPost } 为es6 的解构方法 createPost是从postActions中解构出来的方法
import { createPost } from '../actions/postActions'
class PostForm extends Component {
constructor(props) {
super(props)
this.state = {
title: '',
body: ''
};
}
onChange(e) {//把当前修改的值赋入state
this.setState({
[e.target.name]:e.target.value
})
}
onSubmit(e) {
// 阻止事件传递
e.preventDefault();
// 把表单用的最终数据从state中提取出来,传入请求
const post ={
title:this.state.title,
body:this.state.body
}
// 触发redux 中的action方法,把需要提交的post参数传入
this.props.createPost(post)//把以下原本在页面的fetch请求剪切至actions文件中的PostActions.js文件中
}
render() {
return (
<div>
<h1>添加内容</h1>
<form onSubmit={this.onSubmit.bind(this)}>
<div>
<label >title</label>
<br />
<input type="text" name="title" onChange={this.onChange.bind(this)} defaultValue={this.state.title} />
</div>
<div>
<label >body</label>
<br />
<textarea name="body" id="" cols="30" rows="10" onChange={this.onChange.bind(this)} defaultValue={this.state.body}></textarea>
</div>
<br />
<button type="submit">添加</button>
</form>
</div>
)
}
}
// 规定方法和状态的使用类型
PostForm.propTypes ={
// 第一个为当前的方法
createPost:propTypes.func.isRequired,
// 第二个为数组,是在PostReducer.js中定义的
PostForm : propTypes.array.isRequired
}
// 用connect将PostFromt和createPost连接起来从而达到数据对接
export default connect(null,{createPost})(PostForm);
6.posts.js
在postForm.js传递数据给到posts.js页面
posts.js页面 调用componentWillReceiveProps()钩子函数中去更新渲染
componentWillReceiveProps()钩子函数为组件发生改变触发
在调用钩子函数时判断nextProps下有newPost,就unshift到this.props.posts并渲染出来,
import React, { Component } from 'react'
// 给不前的状态规定一个数据类型,这是react给我们的一个标准
import propTypes from 'prop-types'
//1. 想让Posts使用fetchPost的方法 ,就要使用reducer中提供的connect来连接
import { connect } from 'react-redux'
// fetchPost为在postActions定义的方法
import { fetchPost } from '../actions/postActions'
class Posts extends Component {
componentDidMount() {
/**
* 3.调用fetchPost中的方法,把原本 需要在这里的请求的方法剪切到postAction.js中去
* 触发action操作
*/
this.props.fetchPost()
}
// 在组件发生改变的时候触发,用户添加数据后接收从PostForm.js页面传来的值进行渲染
componentWillReceiveProps(nextProps){
// 在调用钩子函数时判断nextProps下有newPost,就unshift到this.props.posts并渲染出来,
if(nextProps.newPost){
this.props.posts.unshift(nextProps.newPost)
}
}
render() {//展示之前对state数组posts中的数据遍历
// const postsItem = this.state.posts.map(post =>(
// 使用reduce中的数据就这里就不能用this.state,而是改用props
const postsItem = this.props.posts.map(post => (
<div key={post.id}>
<h3>{post.title}</h3>
<p>{post.body}</p>
</div>
))
return (
<div>
{postsItem}
</div>
)
}
}
// 规定方法和状态的使用类型
Posts.propTypes ={
// 第一个为当前的方法
fetchPost:propTypes.func.isRequired,
// 第二个为数组,是在PostReducer.js中定义的
posts : propTypes.array.isRequired
}
/**
* 将返回回来的状态转化成我们的属性props
*/
const mapStateToProps = state => ({
/**
* state中的posts是在reducers中的index.js定义的posts
* items 中posts的属性值是在postReducer.js中定义的初始值
* */
posts: state.posts.items,
newPost:state.posts.item
})
/**
* 2.connect连接
* connect接收两个方法
* connect(mapStateToProps, {fetchPost})
*
* */
export default connect(mapStateToProps, { fetchPost })(Posts);