簡體   English   中英

在chrome開發工具中可見來自redux-store的數據,但實際上無法訪問

[英]Data from redux-store visible in chrome dev tools but cannot actually access

我正在與redux一起使用react,為執行以下操作的動作實現redux-thunk:

  1. Thunk調用axios.get()
  2. 首先, then()語句通過JSON映射,以將鍵和值轉換為前端規范
  3. 第二個then()語句遍歷JSON上的一個屬性(0-5個項目),為每個屬性創建一個數組axios.get()調用者,並包裝在promise中。 該數組被傳遞給async/wait函數,以確保在繼續操作之前,所有這些承諾都得到了解決。
  4. 第三then()語句再次遍歷列表,刪除所有未定義的值,然后成功觸發動作創建者。 在Chrome開發工具上將數據記錄在此處可驗證所有數據是否存在,並且沒有未解決的承諾。
  5. 在Chrome開發工具中將這些有效負載從reducers記錄到映射數據的容器中,會導致相同的問題。 數據存在於控制台中,但無法在任何地方訪問。

我將在下面提供可工作的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中使用,但實際上卻無法訪問?

在渲染功能中,您可以...

{ initialValues && initialValues.buttons ? _that.renderFakeButtons(initialValues.buttons) : '' }

我以為沒有出現。 您實際上並不需要在此處傳遞initialValues作為參數,而只需傳遞所有道具。

嘗試改為執行以下操作:

renderFakeButtons = (props) => {
  if (!props.initialValues.buttons) return;

  // do some rendering here
}

render() {
  const MaybeFakeButtons = this.renderFakeButtons;

  return (
    <div><MaybeFakeButtons {...this.props} /></div>
  )
}

我的猜測是,React無法識別嵌套的更新,因此樹的initialValues三元部分正在更新。 嘗試散布所有道具(如上所示),看看它是否有效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM