Redux-React:调度函数返回的值未传递给子组件
Redux-React: value returned by a dispatch function is not being passed to child component
实际上我是 react-redux 的新手,所以我只需要一些帮助来理解我在这里犯的任何语法或逻辑错误...
基本上,我想显示从另一台服务器获取的报告。函数 'fetchNames' 处理该问题,函数 'fetchdownloadable' 创建一个 returns 一个 link 允许通过身份验证并下载 pdf onClick 报告。
所以我在控制台上调试,我相信代码的执行顺序有问题......当我调试时......我注意到:
首先执行 fetchnames 以获取 json 数组中的所有报告数据...
然后为报告数组中的每个对象和 SampleChild 上的 returns 'undefined' 值调用 fetchDownloadable ...
然后 SampleChild 以未定义的值执行...
然后我们回来执行 fetchDownloadable 函数,该函数在控制台上打印 link 值并在 reducer 上调度操作 returns 而不是 'action.reports_uri' 在 reducer 中。 ..
提前致谢!
SampleParent.js
import React, {Component} from 'react'
import { connect } from 'react-redux'
import { fetchNames, fetchDownloadable } from '../../actions/actions'
import SampleChild from '../ui/SampleChild'
class SampleParent extends Component {
constructor(props) {
super(props);
this.fetchDownloadLink = this.fetchDownloadLink.bind(this)
}
componentDidMount() {
const { dispatch } = this.props
dispatch(fetchNames())
}
fetchDownloadLink(uri){
this.props.dispatch(fetchDownloadable(uri))
}
render() {
return (<div><ul id="myUL">
{this.props.reports.map((report) => (
<li><SampleChild
key={report.id}
label={report.label}
uri={this.fetchDownloadLink("http://localhost:8080/sample"+report.uri+".pdf")}
/></li>))}
</ul></div>
)}
}
function mapStateToProps(state) {
const { reports } = state
return {
reports
}}
export default connect(mapStateToProps)(SampleParent)
SampleChild.js
import React, { Component } from 'react'
export default class SampleChild extends Component {
render() {
const { key, label, uri } = this.props
return (
<div className="inside_SampleChild" id={label}>
{label}
<a href={uri}><img src="../images/pdf-file_128.png" height="25px" width="25px"></img></a>
</div>
)}}
Action.js
import C from '../constants'
import fetch from 'isomorphic-fetch'
export const fetchNames = value => dispatch => {
var obj = { method: 'GET', headers: { 'Authorization': 'Basic ***', 'Accept': 'application/json' },
'credentials': 'include'};
fetch('http://localhost:8080/samplelink', obj)
.then(response => {
if (response.status !== 200) {
throw Error(response.status);
}return response;})
.then((response) => response.json())
.then(resourceLookup => {
var arr = [];
var length = resourceLookup.resourceLookup.length;
for(var i = 0 ; i< length ; i++){
arr.push(resourceLookup.resourceLookup[i]);}
dispatch({
type: C.FETCH_LIST_REPORTS,
reports: arr})}).
catch(error => {
console.log("There was this error" + error);});}
export const fetchReportDownloadable = (uri) => dispatch => {
var obj = {
method: 'GET',
headers: {
'Authorization': 'Basic ***=',
'Accept': 'application/json'
},
'credentials': 'include'
};
fetch(uri, obj)
.then(response => {
if (response.status !== 200) {
throw Error(response.status);
}
return response ;
})
.then((response) => response)
.then(resourceLookup => {
console.log(`resourceLookup URL: ${resourceLookup.url}`)
dispatch({
type: C.FETCH_DOWNLOADABLE,
report_uri: resourceLookup.url
})
}).
catch(error => {
console.log("There was this error" + error);
});}
Reducers.js
import C from '../constants'
import { combineReducers } from 'redux'
export const links = (state=null, action) =>
(action.type === C.FETCH_DOWNLOADABLE) ?
action.report_uri :
state
export const reports = (state=[], action) => {
switch(action.type) {
case C.FETCH_LIST_REPORTS :
return action.reports
default :
return state
}}
const rootReducer = combineReducers({
reports,
links
})
export default rootReducer
我会试着解释发生了什么。
首先,您遇到的第一个问题是您传递了错误的值,或者 uri
in:
的未定义值
<li>
<SampleChild key={report.id} label={report.label}
uri={this.fetchDownloadLink("http://localhost:8080/sample"+report.uri+".pdf")}
/>
</li>
这里 uri
是一个函数,它在第一次渲染时触发,它调度 fetchDownloadable(uri)
动作,但是它不 return 任何值。因此 uri
未定义。
其次,您在减速器中使用了 C.FETCH_REPORT_DOWNLOADABLE
常量。但是,您永远不会调度该类型的操作,该操作会调度 C.FETCHING_DOWNLOADABLE
。因此,reducer 并没有真正做任何事情,所以状态不会改变。我的第二条评论是关于 C.FETCH_LIST_REPORTS
,现在与您无关,所以我错了。
我要做的是从服务器端创建下载 link。将其与报告对象一起发回。这样,您就不需要分派两个操作来列出您的报告。然后,我将在 componentWillMount()
中发送我的操作,一旦完成获取数据,状态将更改 - 如果您再次发送了正确的操作 - 您将在下载 URL在同一个对象中。
更新
好的,我想我现在明白了。然后我要做的是将 uri
作为字符串发送到 SampleChild
,然后当它挂载时我将触发 fetchDownloadable
函数。
样本父
import React, {Component} from 'react'
import { connect } from 'react-redux'
import { fetchNames, fetchReportDownloadable } from '../../actions/actions'
import SampleChild from '../ui/SampleChild'
class SampleParent extends Component {
constructor(props) {
super(props);
this.fetchDownloadLink = this.fetchDownloadLink.bind(this)
}
componentDidMount() {
const { dispatch } = this.props
dispatch(fetchNames())
}
fetchDownloadLink(uri){
this.props.dispatch(fetchReportDownloadable(uri))
}
render() {
return (<div><ul id="myUL">
{this.props.reports.map((report) => (
<li><SampleChild
key={report.id}
label={report.label}
uri={"http://localhost:8080/sample"+report.uri+".pdf"}
download={this.fetchDownloadLink}
/></li>))}
</ul></div>
)}
}
function mapStateToProps(state) {
const { reports } = state
return {
reports
}}
export default connect(mapStateToProps)(SampleParent)
SampleChild
import React, { Component } from 'react'
export default class SampleChild extends Component {
componentDidMount() {
this.props.download(this.props.uri);
}
render() {
const { key, label, uri } = this.props
return (
<div className="inside_SampleChild" id={label}>
{label}
<a href={uri}><img src="../images/pdf-file_128.png" height="25px" width="25px"></img></a>
</div>
)}}
现在应该发生的是,您将首先在 SampleParent
中获取报告,然后将信息传递给 SampleChild
。每当安装 SampleChild
时,它都会触发 fetchDownloadable
操作,在 return 秒内下载发送给它的 uri
。
实际上我是 react-redux 的新手,所以我只需要一些帮助来理解我在这里犯的任何语法或逻辑错误...
基本上,我想显示从另一台服务器获取的报告。函数 'fetchNames' 处理该问题,函数 'fetchdownloadable' 创建一个 returns 一个 link 允许通过身份验证并下载 pdf onClick 报告。
所以我在控制台上调试,我相信代码的执行顺序有问题......当我调试时......我注意到: 首先执行 fetchnames 以获取 json 数组中的所有报告数据... 然后为报告数组中的每个对象和 SampleChild 上的 returns 'undefined' 值调用 fetchDownloadable ... 然后 SampleChild 以未定义的值执行... 然后我们回来执行 fetchDownloadable 函数,该函数在控制台上打印 link 值并在 reducer 上调度操作 returns 而不是 'action.reports_uri' 在 reducer 中。 ..
提前致谢!
SampleParent.js
import React, {Component} from 'react'
import { connect } from 'react-redux'
import { fetchNames, fetchDownloadable } from '../../actions/actions'
import SampleChild from '../ui/SampleChild'
class SampleParent extends Component {
constructor(props) {
super(props);
this.fetchDownloadLink = this.fetchDownloadLink.bind(this)
}
componentDidMount() {
const { dispatch } = this.props
dispatch(fetchNames())
}
fetchDownloadLink(uri){
this.props.dispatch(fetchDownloadable(uri))
}
render() {
return (<div><ul id="myUL">
{this.props.reports.map((report) => (
<li><SampleChild
key={report.id}
label={report.label}
uri={this.fetchDownloadLink("http://localhost:8080/sample"+report.uri+".pdf")}
/></li>))}
</ul></div>
)}
}
function mapStateToProps(state) {
const { reports } = state
return {
reports
}}
export default connect(mapStateToProps)(SampleParent)
SampleChild.js
import React, { Component } from 'react'
export default class SampleChild extends Component {
render() {
const { key, label, uri } = this.props
return (
<div className="inside_SampleChild" id={label}>
{label}
<a href={uri}><img src="../images/pdf-file_128.png" height="25px" width="25px"></img></a>
</div>
)}}
Action.js
import C from '../constants'
import fetch from 'isomorphic-fetch'
export const fetchNames = value => dispatch => {
var obj = { method: 'GET', headers: { 'Authorization': 'Basic ***', 'Accept': 'application/json' },
'credentials': 'include'};
fetch('http://localhost:8080/samplelink', obj)
.then(response => {
if (response.status !== 200) {
throw Error(response.status);
}return response;})
.then((response) => response.json())
.then(resourceLookup => {
var arr = [];
var length = resourceLookup.resourceLookup.length;
for(var i = 0 ; i< length ; i++){
arr.push(resourceLookup.resourceLookup[i]);}
dispatch({
type: C.FETCH_LIST_REPORTS,
reports: arr})}).
catch(error => {
console.log("There was this error" + error);});}
export const fetchReportDownloadable = (uri) => dispatch => {
var obj = {
method: 'GET',
headers: {
'Authorization': 'Basic ***=',
'Accept': 'application/json'
},
'credentials': 'include'
};
fetch(uri, obj)
.then(response => {
if (response.status !== 200) {
throw Error(response.status);
}
return response ;
})
.then((response) => response)
.then(resourceLookup => {
console.log(`resourceLookup URL: ${resourceLookup.url}`)
dispatch({
type: C.FETCH_DOWNLOADABLE,
report_uri: resourceLookup.url
})
}).
catch(error => {
console.log("There was this error" + error);
});}
Reducers.js
import C from '../constants'
import { combineReducers } from 'redux'
export const links = (state=null, action) =>
(action.type === C.FETCH_DOWNLOADABLE) ?
action.report_uri :
state
export const reports = (state=[], action) => {
switch(action.type) {
case C.FETCH_LIST_REPORTS :
return action.reports
default :
return state
}}
const rootReducer = combineReducers({
reports,
links
})
export default rootReducer
我会试着解释发生了什么。
首先,您遇到的第一个问题是您传递了错误的值,或者 uri
in:
<li>
<SampleChild key={report.id} label={report.label}
uri={this.fetchDownloadLink("http://localhost:8080/sample"+report.uri+".pdf")}
/>
</li>
这里 uri
是一个函数,它在第一次渲染时触发,它调度 fetchDownloadable(uri)
动作,但是它不 return 任何值。因此 uri
未定义。
其次,您在减速器中使用了 C.FETCH_REPORT_DOWNLOADABLE
常量。但是,您永远不会调度该类型的操作,该操作会调度 C.FETCHING_DOWNLOADABLE
。因此,reducer 并没有真正做任何事情,所以状态不会改变。我的第二条评论是关于 C.FETCH_LIST_REPORTS
,现在与您无关,所以我错了。
我要做的是从服务器端创建下载 link。将其与报告对象一起发回。这样,您就不需要分派两个操作来列出您的报告。然后,我将在 componentWillMount()
中发送我的操作,一旦完成获取数据,状态将更改 - 如果您再次发送了正确的操作 - 您将在下载 URL在同一个对象中。
更新
好的,我想我现在明白了。然后我要做的是将 uri
作为字符串发送到 SampleChild
,然后当它挂载时我将触发 fetchDownloadable
函数。
样本父
import React, {Component} from 'react'
import { connect } from 'react-redux'
import { fetchNames, fetchReportDownloadable } from '../../actions/actions'
import SampleChild from '../ui/SampleChild'
class SampleParent extends Component {
constructor(props) {
super(props);
this.fetchDownloadLink = this.fetchDownloadLink.bind(this)
}
componentDidMount() {
const { dispatch } = this.props
dispatch(fetchNames())
}
fetchDownloadLink(uri){
this.props.dispatch(fetchReportDownloadable(uri))
}
render() {
return (<div><ul id="myUL">
{this.props.reports.map((report) => (
<li><SampleChild
key={report.id}
label={report.label}
uri={"http://localhost:8080/sample"+report.uri+".pdf"}
download={this.fetchDownloadLink}
/></li>))}
</ul></div>
)}
}
function mapStateToProps(state) {
const { reports } = state
return {
reports
}}
export default connect(mapStateToProps)(SampleParent)
SampleChild
import React, { Component } from 'react'
export default class SampleChild extends Component {
componentDidMount() {
this.props.download(this.props.uri);
}
render() {
const { key, label, uri } = this.props
return (
<div className="inside_SampleChild" id={label}>
{label}
<a href={uri}><img src="../images/pdf-file_128.png" height="25px" width="25px"></img></a>
</div>
)}}
现在应该发生的是,您将首先在 SampleParent
中获取报告,然后将信息传递给 SampleChild
。每当安装 SampleChild
时,它都会触发 fetchDownloadable
操作,在 return 秒内下载发送给它的 uri
。