我正在使用 react with redux,为执行以下操作的操作实现 redux-thunk:
- 电话
axios.get()
- 第一
then()
条语句映射到 JSON 以将键和值转换为前端规范 - 第二
then()
条语句遍历 JSON 上的一个属性(0 - 5 项)axios.get()
,为每个属性创建一个调用数组,封装在 Promise 中。这个数组被传递给一个async/wait
函数,确保这些承诺在继续之前都得到解决。 - 第三
then()
条语句再次遍历列表,删除任何未定义的值,然后成功触发动作创建者。在 Chrome 开发工具上记录数据可以验证所有数据都存在,并且没有未解决的承诺。 - 在 Chrome 开发工具中将此有效负载从 reducer 记录到映射数据的容器中,会导致相同的问题。数据存在于控制台中,但无法在任何地方访问。
我将在下面提供有效的 js,尽管它在此代码段中不起作用:
/* - - - - - - Actions - - - - - - -
Using thunk, promises, and async/await to insure data is present before sending to reducer
*/
export function getSingleMessage(id, callback) {
return function (dispatch) {
const request = axios.get(`${ROOT_URL}getDialogue.php?message_id=${id}`)
.then((resp) => {
// Just reformatting JSON
const { data } = resp;
console.log('message: ', data)
let formValues = {};
let messageIds = [];
formValues.dialogue_query = data.message_query;
formValues.dialogue_text = data.message;
formValues.message_id = data.messages_id;
if (data.attachment) {
formValues.attachment_text = data.attachment.text;
formValues.attachment_fallback = data.attachment.fallback;
formValues.image_url = data.attachment.image_url;
if (data.attachment.actions) {
/*
1) these buttons need unique id's
2) the last unique id needs to not collide with any other id's of new buttons
// Map through actions
if key is 'name'
button_text
if key is 'type'
action
*/
let key = 0;
formValues.buttons = data.attachment.actions.map( action => {
let newAction = {};
Object.keys(action).forEach( key => {
let curr = action[key];
let newCurrArr;
let newCurr;
if (key === 'name') {
newAction.button_text = curr;
}
if (key === 'value') {
if (curr.includes('Value[')) {
newCurrArr = curr.split('=');
newCurr = newCurrArr.pop();
newAction.button_action = newCurr;
curr = newCurrArr.join('=')
console.log('CURRRRRRR: ', curr)
}
if (curr.includes('message_id=')) {
newCurrArr = curr.split('=').pop();
console.log('NEWCURRARR: ', newCurrArr)
let newNewCurrArr = newCurrArr.split('&');
console.log('NEWNEWCURRARR: ', newNewCurrArr)
newCurr = newNewCurrArr.shift();
messageIds.push(newCurr);
newAction.message_id = Number(newCurr);
}
}
});
newAction.id = key;
key++;
return newAction;
})
}
}
return [formValues, messageIds]
})
.then((resp) => {
// creating array of promises, and resolving with async/await
const formValues = resp[0];
const messageIds = resp[1];
const promises = messageIds.map((id) => axios.get(`${ROOT_URL}getDialogue.php?message_id=${id}`));
console.log('PROMISES!!!!!! ', promises)
if (formValues.buttons) {
async function getPreviewMessages() {
let resolvedPreviewMessages = await Promise.all(promises);
return formValues.buttons.map((button, i) => {
// setting previewMessages to buttons
button.previewMessage = resolvedPreviewMessages[i];
return button;
})
}
getPreviewMessages();
}
return formValues;
})
.then((formValues) => {
//
console.log('RESP: ', formValues)
// cleans up any null or undefined values
for (let key in formValues) {
if (formValues[key] === 'null' || formValues[key] === 'undefined') {
formValues[key] = '';
console.log(`formValues[${key}] = ${formValues[key]}`);
}
console.log(`formValues[${key}] = ${formValues[key]}`);
}
console.log('formValues: ', formValues)
dispatch(fireOffSingleMessage({data: formValues}));
})
.catch((err) => {
console.log(err)
return err;
})
console.log('requesssssssst: ', request)
callback();
}
}
function fireOffSingleMessage(request) {
// data is all resolved in Chrome Dev Tools
console.log('FIRED OFF SINGLE MESSAGE~~~~~~', request)
return {
type: GET_SINGLE_MESSAGE,
payload: request,
}
}
// - - - - - - Reducer - - - - - - -
import { GET_SINGLE_MESSAGE, REFRESH_SINGLE_MESSAGE, ADD_BUTTON_EDIT, EDIT_BUTTON_EDIT, DELETE_BUTTON_EDIT } from '../constants';
export default (state = {}, action) => {
switch(action.type) {
case GET_SINGLE_MESSAGE:
console.log('Data is present!: ', action.payload.data.buttons)
return action.payload;
case REFRESH_SINGLE_MESSAGE:
return {}
// Not involved
case ADD_BUTTON_EDIT:
console.log('ADD_BUTTON_EDIT reducer fired off!', state);
if (Array.isArray(state.data.buttons) && state.data.buttons.length > 0) {
return {
...state,
data: {... state.data, buttons: [...state.data.buttons, action.button]}
};
} else {
return {
...state,
data: {... state.data, buttons: [action.button]}
};
}
case EDIT_BUTTON_EDIT:
console.log('EDIT_BUTTON_EDIT reducer fired off!', state);
const newStateEdit = state.data.buttons.map(button => {
if (button.id === action.button.id) {
console.log('button.id: ', button.id)
console.log('action.button.id: ', action.button.id)
return action.button;
} else {
return button;
}
})
return {
...state,
data: {... state.data, buttons: newStateEdit}
};
case DELETE_BUTTON_EDIT:
console.log('DELETE_BUTTON_EDIT reducer fired off!', state);
const newStateDelete = state.data.buttons.filter(button => button.id !== action.target);
return {
...state,
data: {... state.data, buttons: newStateDelete}
};
default:
return state;
}
}
// - - - - Root Reducer - - - - -
import { combineReducers } from 'redux';
import { reducer as formReducer } from 'redux-form';
import getAllDialogs from './getAllDialogs-reducer.js';
import handleMessages from './messages-reducer.js';
import handleMessage from './message-reducer.js'
import handleMessageId from './messageId-reducer.js'
import updateButtons from './buttons-reducer.js';
import renderButtonForm from './buttonForm-reducer.js';
import handleId from './buttonId-reducer.js';
import handleNewMessageQuery from './newMessageQuery-reducer.js';
import handleMessageQueries from './messageQueries-reducer.js';
import handleButton from './button-reducer.js';
import handleReRenderToggle from './reRenderToggle-reducer.js';
import handleContext from './context-reducer.js';
const rootReducer = combineReducers({
dialogs: getAllDialogs,
messages: handleMessages,
message: handleMessage,
messageId: handleMessageId,
buttons: updateButtons,
buttonForm: renderButtonForm,
button: handleButton,
buttonId: handleId,
reRender: handleReRenderToggle,
newMessageQuery: handleNewMessageQuery,
messageQueries: handleMessageQueries,
context: handleContext,
form: formReducer,
});
export default rootReducer;
// - - - - - container - - - - -
renderFakeButtons(buttons = []) {
const _that = this;
buttons.forEach((button, i) => {console.log(button)});
const { history, deleteButton, renderButtonForm, reRenderToggle, getSingleMessage, getSinglePreviewMessage } = this.props;
// DATA LOGS IN DEV TOOLS!!!!
console.log('BUTTONS: ', buttons)
return buttons.map((button) => {
// DATA LOGS IN DEV TOOLS!!!
console.log('BUTTON: ', button)
return (
<div
className="top-margin"
key={button.id}>
<div className="row">
<Card>
<CardHeader
title={`Button Text: ${button.button_text}`}
subtitle={`Button Action: ${button.button_action}`}
actAsExpander={true}
showExpandableButton={true}
/>
<CardText expandable={true}>
<div>
{/*THIS IS WHERE I WOULD ACCESS THE PROPERTY EXPLICITLY*/}
{JSON.stringify(button)}
</div>
</CardText>
<CardActions>
<FlatButton
label={`Next Message: ${button.message_id}`}
onTouchTap={function(){
getSingleMessage(button.message_id, () => {
history.push(`/message/edit/${button.message_id}`);
})
}
}
/>
<FlatButton
label="Delete Button"
onTouchTap={() => { deleteButton(button.id, 'edit'); reRenderToggle(); }}
/>
</CardActions>
</Card>
</div>
</div>
)}
);
}
render() {
const _that = this;
const { state, onSubmit, onTest, onBack, renderMessageQuerySelect, renderInputFields, renderTextAreaFields, injectButtonForm, renderUserTestSelectOptions } = this;
const { messages, getMessageId, messageId, handleSubmit, renderButtonForm, buttons, reset, buttonForm, refreshSingleMessage, toggleMessageQueryField, newMessageQuery, initialValues, addButtons } = this.props;
let titleName;
if (messages.messages && messages.messages.dialog_name) {
titleName = messages.messages.dialog_name;
} else if (messages.messages && messages.messages.messageQuery) {
titleName = messages.messages.messageQuery
}
return (
<div>
<MuiThemeProvider>
<div className="row">
<div className="col-md-6">
<form onSubmit={handleSubmit(onSubmit.bind(this))}>
<div className="form-group">
<h4> Edit Message {messageId} from "{titleName}" </h4>
<Field
label="Message Query"
name="dialogue_query"
component={newMessageQuery ? renderInputFields : renderMessageQuerySelect.bind(this)}
/>
New
<input
type="checkbox"
onClick={toggleMessageQueryField}
/>
</div>
<Field
label="Text of Message"
name="dialogue_text"
component={renderTextAreaFields}
/>
<Field
label="Attachment Text"
name="attachment_text"
component={renderInputFields}
/>
{ state.error !== null ? <div className="form-group has-danger"><div className="text-help">{state.error}</div></div> : null }
<Field
label="Attachment Fallback"
name="attachment_fallback"
component={renderInputFields}
/>
{ state.error !== null ? <div className="form-group has-danger"><div className="text-help">{state.error}</div></div> : null }
<Field
label="Image Url"
name="image_url"
component={renderInputFields}
/>
<div className="form-group">
<div>
<div
className="btn btn-primary"
onClick={function() {
renderButtonForm();
}}
>
Click to Add Buttons
</div>
<div>
{ initialValues && initialValues.buttons ? _that.renderFakeButtons(initialValues.buttons) : '' }
</div>
</div>
</div>
<Field
label="Test Primary User"
name="primary_test_user_id"
component={renderUserTestSelectOptions}
/>
<Field
label="Test Secondary User"
name="secondary_test_user_id"
component={renderUserTestSelectOptions}
/>
<button
type="submit"
className="btn btn-primary"
>
Submit
</button>
<button
type="submit"
className="btn btn-primary buttons-margin"
onClick={handleSubmit(onTest.bind(this))}
>
Test
</button>
<div className="btn btn-primary buttons-margin" onClick={reset}>Reset to Original</div>
<div className="btn btn-danger buttons-margin" onClick={onBack.bind(this)}>Back</div>
</form>
</div>
<div className="col-md-5">
<div className="row">
<div className="col-md-12">
{injectButtonForm(buttonForm)}
</div>
</div>
<div className="row">
<div className="col-md-12">
<div className="bottom-top-margin">
</div>
</div>
</div>
</div>
</div>
</MuiThemeProvider>
</div>
);
}
}
function validate(values) {
const errors = {};
if (!values.dialogue_text) {
errors.dialogue_text = "Enter message text";
}
return errors;
}
MessageEdit = reduxForm({
validate,
form: 'MessageEditForm', // a unique name for this form
enableReinitialize: true,
})(MessageEdit)
MessageEdit = connect(
state => {
const newState = {
dialogs: state.dialogs,
messages: state.messages,
messageId: state.messageId,
initialValues: state.message.data,
buttonForm: state.buttonForm.isRendered,
buttonId: state.buttonId,
messageQueries: state.messageQueries,
reRender: state.reRender,
newMessageQuery: state.newMessageQuery,
context: state.context,
}
console.log('MessageEdit newState: ', newState);
return newState },
{ addButtons, postNewMessage, testMessage, getSingleMessage, refreshSingleMessage, deleteMessage, getDialogMessages, refreshButtons, deleteButton, refreshButtonId, refreshButtons, renderButtonForm, unRenderButtonForm, toggleMessageQueryField, getMessageId, getMessageQueries, reRenderToggle }
)(MessageEdit)
export default MessageEdit;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
根据 Chrome 开发工具,为什么我的数据在我的 THUNK 中可用,但实际上无法访问?