为什么映射状态到道具不明确? [英] Why does mapping state to props give undefined?
问题描述
帖子
操作和reducers的问题,但一旦添加了一个 searchQueries
节,它只显示 searchQueries
道具的未定义的
值。 我尽可能地复制它,并修改第二组动作/ reducers,但我仍然以 undefined
道具在 searchQueries
的情况下。我收到所有道具,包括帖子
的默认值。以下是每个代码的代码:
/actions/posts.js:
'axios'的导入axios
导出功能postsHasErrored(bool){
return {
type:'POSTS_HAS_ERRORED',
hasErrored:bool
}
}
导出功能postsIsLoading(bool){
return {
type:'POSTS_IS_LOADING',
isLoading:bool
}
}
导出功能postsFetchDataSuccess(posts){
return {
type:'POSTS_FETCH_DATA_SUCCESS',
posts
}
}
导出功能totalPagesFetchDataSuccess(totalPages){
return {
type:'TOTAL_PAGES_FETCH_DATA_SUCCESS',
totalPages
}
}
导出函数postsFetchData(url){
return(dispatch)=> {
dispatch(postsIsLoading(true))
axios.get(url)
.then(res => {
if(res.status! 200)throw Error(res.statusText)
dispatch(postsIsLoading(false))
return res
})
.then(res => {
dispatch postsFetchDataSuccess(res.data))
dispatch(totalPagesFetchDataSuccess(res.headers ['x-wp-totalpages']))
})
.catch(()=> dispatch(postsHasErrored (true)))
}
}
/actions/searchQueries.js :
const readLocation =(name)=> {
let parameter = getParameterByName(name);
if(name ==='categories'){
if(parameter){
parameter = parameter.split(',')
for(let i = 0; i < parameter.length; i ++)parameter [i] = parseInt(parameter [i],10)
}
else parameter = []
}
if (参数=== null){
if(name ==='search')parameter =''
if(name ==='page')parameter = 1
}
console.log(参数)
返回参数
}
导出函数setSearchString(searchString){
return {
类型:'SET_SEARCH_STRING',
searchString
}
}
导出函数setSearchCategories(searchCategories){
return {
type: 'SET_SEARCH_CATEGORIES',
searchCategories
}
}
导出函数setSearchPage(searchPage){
return {
type:'SET_SEARCH_PAGE'
searchPage
}
}
export f unction searchQueriesSetting(){
return(dispatch)=> {
dispatch(setSearchString(readLocation('search')))
dispatch(setSearchCategories(readLocation('categories')))
dispatch(setSearchPage(readLocation('page' b $ b}
}
/reducers/posts.js:
export function postsHasErrored(state = false,action){
switch(action.type){
case'POSTS_HAS_ERRORED'
return action.hasErrored
默认值:
返回状态
}
}
导出函数postsIsLoading(state = false,动作){
switch(action.type){
case'POSTS_IS_LOADING':
return action.isLoading
默认值:
返回状态
}
}
导出功能帖子(state = [],action){
switch(action.type){
case'POSTS_FETCH_DATA_SUCCESS':
return action.posts
默认值:
返回状态
}
}
导出功能总共页数(状态= 1,动作){
switch(action.type){
case'TOTAL_PAGES_FETCH_DATA_SUCCESS':
return parseInt(action.totalPages,10)
默认值:
返回状态
}
}
/ reducers /searchQueries.js:
导出功能searchString(state ='',action){
switch(action.type ){
case'SET_SEARCH_STRING':
return action.searchString
默认值:
返回状态
}
}
export function searchCategories(state = [],action){
switch(action.type){
case'SET_SEARCH_CATEGORIES':
return action.searchCategories
默认值:
返回状态
}
}
导出函数searchPage(state = 1,action){
switch(action.type){
case'SET_SEARCH_PAGE':
return action.searchPage
默认值:
return sta te
}
}
/reducers/index.js:
import {combineReducers} from'redux'
import {posts,totalPages,postsHasErrored,postsIsLoading} from'./posts'
import {searchString,searchCategories,searchPage} from'./searchQueries'
export default combineReducers({
posts,
postsHasErrored,
postsIsLoading,
totalPages,
searchString,
searchCategories,
searchPage
})
/components/PostsList.js
//依赖项
import React, {component} from'react'
从'axios'导入axios
import {connect}从'react-redux'
//组件
import PostsListItem from'./PostsListItem'
从'./PostsPages'导入的帖子
//动作
从'../actions/posts'导入{postsFetchData}
import {searchQueriesSetting} from'../action s / searchQueries'
// styles
import'../styles/css/postsList.css'
//共享模块
import {createSearchUrl} from'../sharedModules / sharedModules'
class PostsList extends Component {
componentWillReceiveProps(nextProps){
if(nextProps.searchPage!== this.props.searchPage)this.componentDidMount ()
}
componentDidMount(){
this.props.searchQueriesSetting()
this.props.fetchData(createSearchUrl(
'http:/ / localhost / wordpress-api / wp-json / wp / v2 / posts?per_page = 1',
this.props.searchCategories,
this.props.searchString,
this.props。
render(){
console.log(this.props)
const {isLoading,hasErrored, post} = this.props
if ;
const postsList = posts.map(post =>< PostsListItem post = {post} key = {post.id} />)
return(
< div className ='posts-list'>
{postsList}
< PostsPages />
< / div>
)
}
}
const mapStateToProps =(state)=> {
return {
posts:state.posts,
hasErrored:state.postsHasErrored,
isLoading:state.postsIsLoading,
searchCategories:state.searchCategories,
searchString:state.searchString,
searchPage:state.searchPage
}
}
const mapDispatchToProps =(dispatch)=> {
return {
fetchData:(url)=> dispatch(postsFetchData(url)),
searchQueriesSetting:()=> dispatch(searchQueriesSetting())
}
}
导出默认连接(mapStateToProps,mapDispatchToProps)(PostsList)
/components/PostsPages.js
//依赖项
导入反应,{component} from'react'
import {link} from'react-router-dom'
import {connect} from'react-redux'
// actions
import {setSearchPage} from'../actions/searchQueries'
//共享模块
import {createSearchUrl} from'../sharedModules/sharedModules'
class PostsPages extends Component {
isLinkEdgy =(pageNumber)=> {
if(parseInt(pageNumber,10)< = 1)return''
if(parseInt(pageNumber,10)> = parseInt(this.props.totalPages,10))返回此。 props.totalPages
return pageNumber
}
render(){
const {totalPages,currentPage,searchCategories,searchString,setSearchPage} = this.props
const previousUrl = createSearchUrl('/ blog',searchCategories,searchString,this.isLinkEdgy(parseInt(currentPage,10) - 1))
const nextUrl = createSearchUrl('/ blog',searchCategories,searchString, this.isLinkEdgy(parseInt(currentPage,10)+ 1))
return(
< div className ='posts-pages'>
< ul className =' post-pages-list'>
< li>< link to = {previousUrl} onClick = {()=> setSearchPage(this.isLinkEdgy(parseInt(currentPage,10) - 1))}> ;上一页< / Link>< / li>
< li>< link to = {nextUrl} onClick = {()=> setSearchPage(this.i sLinkEdgy(parseInt(currentPage,10)+ 1))}>下一页< / Link>< / li>
< / ul>
< / div>
)
}
}
const mapStateToProps =(state)=> {
return {
totalPages:state.totalPages,
currentPage:state.searchPage,
searchCategories:state.searchCategories,
searchString:state.searchString
}
}
const mapDispatchToProps =(dispatch)=> {
return {
setSearchPage:(searchPage)=> dispatch(setSearchPage(searchPage))
}
}
导出默认连接(mapStateToProps,mapDispatchToProps)(postsPages)
这是因为您正在访问错误的状态。看看你的 combineReducers
call:
export default combineReducers({
帖子,
postsHasErrored,
postsIsLoading,
totalPages,
setSearchString,
setSearchCategories,
setSearchPage
} )
Per Redux文档:
combineReducers(reducers )
状态对象的形状与传递的
reducers的键匹配
。
因此,您的状态
这个:
{
posts:...,
postsHasErrored:...,
postsIsLoading:...,
totalPages:...,
setSearchString:...,
setSearchCategories:...,
setSearchPage:...
}
在你身上
currentPage:state.searchPage,
searchCategories:state.searchCategories,
searchString:state.searchString
由于 state.searchPage
而另外两个不存在于状态
对象中,你得到 undefined
。相反,请确保您访问与reducers具有相同名称的键:
currentPage:state.setSearchPage,
searchCategories:state.setSearchCategories,
searchString:state.setSearchString
或者只是重命名您的reducers (这是现在更好的,因为它们是误会)。删除reducer上的 set
前缀,它们不是动作。
I'm having a problem with my setup of Redux. I didn't have a problem with single file of posts
actions and reducers, but as soon as added a searchQueries
sections, it shows only undefined
values for the searchQueries
props.
I've tried copying it as far as I can and modifying it for the second set of actions/reducers, but I'm still ending up with undefined
props in the case of searchQueries
. I'm getting all the props, including the default values in the case of posts
. Here's the code for each of these:
/actions/posts.js:
import axios from 'axios'
export function postsHasErrored(bool) {
return {
type: 'POSTS_HAS_ERRORED',
hasErrored: bool
}
}
export function postsIsLoading(bool) {
return {
type: 'POSTS_IS_LOADING',
isLoading: bool
}
}
export function postsFetchDataSuccess(posts) {
return {
type: 'POSTS_FETCH_DATA_SUCCESS',
posts
}
}
export function totalPagesFetchDataSuccess(totalPages) {
return {
type: 'TOTAL_PAGES_FETCH_DATA_SUCCESS',
totalPages
}
}
export function postsFetchData(url) {
return (dispatch) => {
dispatch(postsIsLoading(true))
axios.get(url)
.then(res => {
if (res.status !== 200) throw Error(res.statusText)
dispatch(postsIsLoading(false))
return res
})
.then(res => {
dispatch(postsFetchDataSuccess(res.data))
dispatch(totalPagesFetchDataSuccess(res.headers['x-wp-totalpages']))
})
.catch(() => dispatch(postsHasErrored(true)))
}
}
/actions/searchQueries.js:
const readLocation = (name) => {
let parameter = getParameterByName(name);
if (name === 'categories') {
if (parameter) {
parameter = parameter.split(',')
for (let i = 0; i < parameter.length; i++) parameter[i] = parseInt(parameter[i], 10)
}
else parameter = []
}
if (parameter === null) {
if (name === 'search') parameter = ''
if (name === 'page') parameter = 1
}
console.log(parameter)
return parameter
}
export function setSearchString(searchString) {
return {
type: 'SET_SEARCH_STRING',
searchString
}
}
export function setSearchCategories(searchCategories) {
return {
type: 'SET_SEARCH_CATEGORIES',
searchCategories
}
}
export function setSearchPage(searchPage) {
return {
type: 'SET_SEARCH_PAGE',
searchPage
}
}
export function searchQueriesSetting() {
return (dispatch) => {
dispatch(setSearchString(readLocation('search')))
dispatch(setSearchCategories(readLocation('categories')))
dispatch(setSearchPage(readLocation('page')))
}
}
/reducers/posts.js:
export function postsHasErrored(state = false, action) {
switch (action.type) {
case 'POSTS_HAS_ERRORED':
return action.hasErrored
default:
return state
}
}
export function postsIsLoading(state = false, action) {
switch (action.type) {
case 'POSTS_IS_LOADING':
return action.isLoading
default:
return state
}
}
export function posts(state = [], action) {
switch (action.type) {
case 'POSTS_FETCH_DATA_SUCCESS':
return action.posts
default:
return state
}
}
export function totalPages(state = 1, action) {
switch (action.type) {
case 'TOTAL_PAGES_FETCH_DATA_SUCCESS':
return parseInt(action.totalPages, 10)
default:
return state
}
}
/reducers/searchQueries.js:
export function searchString(state = '', action) {
switch (action.type) {
case 'SET_SEARCH_STRING':
return action.searchString
default:
return state
}
}
export function searchCategories(state = [], action) {
switch (action.type) {
case 'SET_SEARCH_CATEGORIES':
return action.searchCategories
default:
return state
}
}
export function searchPage(state = 1, action) {
switch (action.type) {
case 'SET_SEARCH_PAGE':
return action.searchPage
default:
return state
}
}
/reducers/index.js:
import { combineReducers } from 'redux'
import { posts, totalPages, postsHasErrored, postsIsLoading } from './posts'
import { searchString, searchCategories, searchPage } from './searchQueries'
export default combineReducers({
posts,
postsHasErrored,
postsIsLoading,
totalPages,
searchString,
searchCategories,
searchPage
})
/components/PostsList.js
// dependencies
import React, { Component } from 'react'
import axios from 'axios'
import { connect } from 'react-redux'
// components
import PostsListItem from './PostsListItem'
import PostsPages from './PostsPages'
// actions
import { postsFetchData } from '../actions/posts'
import { searchQueriesSetting } from '../actions/searchQueries'
// styles
import '../styles/css/postsList.css'
// shared modules
import { createSearchUrl } from '../sharedModules/sharedModules'
class PostsList extends Component {
componentWillReceiveProps(nextProps) {
if (nextProps.searchPage !== this.props.searchPage) this.componentDidMount()
}
componentDidMount() {
this.props.searchQueriesSetting()
this.props.fetchData(createSearchUrl(
'http://localhost/wordpress-api/wp-json/wp/v2/posts?per_page=1',
this.props.searchCategories,
this.props.searchString,
this.props.searchPage
))
}
render() {
console.log(this.props)
const { isLoading, hasErrored, posts } = this.props
if (isLoading) return <div className='posts-list'><h2 className='loading'>Loading...</h2></div>
const postsList = posts.map(post => <PostsListItem post={post} key={post.id} />)
return (
<div className='posts-list'>
{postsList}
<PostsPages />
</div>
)
}
}
const mapStateToProps = (state) => {
return {
posts: state.posts,
hasErrored: state.postsHasErrored,
isLoading: state.postsIsLoading,
searchCategories: state.searchCategories,
searchString: state.searchString,
searchPage: state.searchPage
}
}
const mapDispatchToProps = (dispatch) => {
return {
fetchData: (url) => dispatch(postsFetchData(url)),
searchQueriesSetting: () => dispatch(searchQueriesSetting())
}
}
export default connect(mapStateToProps, mapDispatchToProps)(PostsList)
/components/PostsPages.js
// dependencies
import React, { Component } from 'react'
import { Link } from 'react-router-dom'
import { connect } from 'react-redux'
// actions
import { setSearchPage } from '../actions/searchQueries'
// shared modules
import { createSearchUrl } from '../sharedModules/sharedModules'
class PostsPages extends Component {
isLinkEdgy = (pageNumber) => {
if (parseInt(pageNumber, 10) <= 1) return ''
if (parseInt(pageNumber, 10) >= parseInt(this.props.totalPages, 10)) return this.props.totalPages
return pageNumber
}
render() {
const { totalPages, currentPage, searchCategories, searchString, setSearchPage } = this.props
const previousUrl = createSearchUrl('/blog', searchCategories, searchString, this.isLinkEdgy(parseInt(currentPage, 10) - 1))
const nextUrl = createSearchUrl('/blog', searchCategories, searchString, this.isLinkEdgy(parseInt(currentPage, 10) + 1))
return (
<div className='posts-pages'>
<ul className='posts-pages-list'>
<li><Link to={previousUrl} onClick={() => setSearchPage(this.isLinkEdgy(parseInt(currentPage, 10) - 1))}>Prev page</Link></li>
<li><Link to={nextUrl} onClick={() => setSearchPage(this.isLinkEdgy(parseInt(currentPage, 10) + 1))}>Next page</Link></li>
</ul>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
totalPages: state.totalPages,
currentPage: state.searchPage,
searchCategories: state.searchCategories,
searchString: state.searchString
}
}
const mapDispatchToProps = (dispatch) => {
return {
setSearchPage: (searchPage) => dispatch(setSearchPage(searchPage))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(PostsPages)
That's because you're accessing the wrong par of state. Take a look at your combineReducers
call:
export default combineReducers({
posts,
postsHasErrored,
postsIsLoading,
totalPages,
setSearchString,
setSearchCategories,
setSearchPage
})
combineReducers(reducers)
The shape of the state object matches the keys of the passed
reducers
.
Thus your state
object actually looks like this:
{
posts: ...,
postsHasErrored: ...,
postsIsLoading: ...,
totalPages: ...,
setSearchString: ...,
setSearchCategories: ...,
setSearchPage: ...
}
In your mapDispatchToProps
, you're trying to access the wrong part of state:
currentPage: state.searchPage,
searchCategories: state.searchCategories,
searchString: state.searchString
Since state.searchPage
and the other two don't exist in the state
object, you get undefined
. Instead, make sure you access the keys which have the same name as the reducers:
currentPage: state.setSearchPage,
searchCategories: state.setSearchCategories,
searchString: state.setSearchString
Or just rename your reducers (which would be preferable as they are misnomers right now). Get rid of the set
prefix on the reducers, they are not actions.
这篇关于为什么映射状态到道具不明确?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!