Изменить массив, взятый из reactjs контекста локально, без обновления фактического массива в контексте - PullRequest
1 голос
/ 26 мая 2020

Я новичок в использовании контекста в реакции. У меня есть массив объектов, содержащихся в контексте, подобном этому:

allQueries: [
  {
    id: 0,
    operator: 'AND',
    field: 'current_full_path',
    from: 'xyz',
    to: '',
    selection: '',
    addDisabled: true,
  },
  {
    id: 1,
    operator: 'AND',
    field: 'user',
    from: 'Bob',
    to: '',
    selection: '',
    addDisabled: true,
  },
  {
    id: 2,
    operator: 'AND',
    field: 'package_type',
    from: '',
    to: '',
    selection: 'large',
    addDisabled: true,
  },
  {
    etc...
  }
],

Версия этого будет отправлена ​​как тело запроса на сервер, который вернет набор данных на основе запроса.

Проблема, с которой я столкнулся, заключается в том, чтобы очистить вышеуказанное перед отправкой. Мне нужно удалить поле «id», поле «addDisabled» и т. Д. c. et c. и мне нужно сделать это без изменения фактического массива объектов, содержащихся в контексте, потому что его нужно использовать снова после этого.

Я пробовал заполнить локальное состояние массивом из контекста и проведение изменений там. Я также попытался установить для него пустой массив в новом контексте и внести в него изменения, однако, что бы я ни делал, исходный массив allQueries также продолжает обновляться, а это означает, что пользователи не могут вносить уточнения в свой поиск после начальный поиск был произведен.

Я в тупике - есть ли у кого-нибудь идеи?

ps - как указано выше, в настоящее время пытаюсь переместить его в другой контекст, чтобы обойти this - для более полной детализации полный код компонента приведен ниже:

Спасибо

import React, { useEffect, useContext } from 'react';
import AndQueryContext from '../../context/andQuery/andQueryContext';
import SendQueryContext from '../../context/sendQuery/sendQueryContext';

const SearchButton = () => {
  const andQueryContext = useContext(AndQueryContext);
  const sendQueryContext = useContext(SendQueryContext);

  const { allQueries } = andQueryContext;
  const { objToSend, updateObjToSend } = sendQueryContext;

  useEffect(() => {
    updateObjToSend(allQueries);
    //eslint-disable-next-line
  }, [allQueries]);

  const prepareQuery = (objToSend) => {
    console.clear('objToSend: ', objToSend);
    const queryObj = {};

    prepareAndQueries(objToSend, queryObj);
    console.log('queryObj after: ', queryObj);

  };

  const prepareAndQueries = (objToSend, queryObj) => {
    console.log('objToSend: ', objToSend);
    objToSend.map((item, index) => {
      delete item.id;
      delete item.addDisabled;
      if (
        item.field === 'package_type' ||
        item.field === 'document_type' ||
        item.field === 'user' ||
        item.field === 'status'
      ) {
        delete item.from;
        delete item.to;
      }
      if (
        item.field === 'current_full_path' ||
        item.field === 'date' ||
        item.field === 'size'
      ) {
        delete item.selection;
      }
    });

    console.log('objToSend after filter: ', objToSend);
    console.log('allQueries after filter: ', allQueries);

    queryObj.initial = objToSend;

    return queryObj;
  };

  return (
    <div className='col-2'>
      <button
        className='btn btn-labelled btn-info btn-sm'
        onClick={(e) => prepareQuery(objToSend)}
      >
        <span className='btn-label'>
          <i className='fas fa-search'></i>
        </span>
        Search
      </button>
    </div>
  );
};

export default SearchButton;

Хук контекста вводит другой файл AndQueryState. js:

import React, { useReducer } from 'react';
// import axios from 'axios';
import AndQueryContext from './andQueryContext';
import AndQueryReducer from './andQueryReducer';

import {
  UPDATE_ALL_QUERIES,
  UPDATE_DROPDOWN_ARRAY,
  UPDATE_REMOVED_DROPDOWN,
  UPDATE_USE_OR,
  // SEND_QUERY,
} from '../types';

const AndQueryState = (props) => {
  const initialState = {
    initialQuery: {
      id: 0,
      operator: 'AND',
      field: 'current_full_path',
      from: '',
      to: '',
      selection: '',
      addDisabled: true,
    },
    allQueries: [
      {
        id: 0,
        operator: 'AND',
        field: 'current_full_path',
        from: '',
        to: '',
        selection: '',
        addDisabled: true,
      },
    ],
    dropDownFieldsInitial: [
      'current_full_path',
      'date',
      'size',
      'package_type',
      'document_type',
      'user',
      'status',
    ],
    dropDownFields: [
      'current_full_path',
      'date',
      'size',
      'package_type',
      'document_type',
      'user',
      'status',
    ],
    // old ones
    sendToApi: 'https://api.github.com/search/users?q=stefemil',
    loading: false,
    useOr: 0, // determines whether OR clauses are to be used
  };

  const [state, dispatch] = useReducer(AndQueryReducer, initialState);

  const updateAllQueries = (allQueriesFromComp) => {
    dispatch({
      type: UPDATE_ALL_QUERIES,
      payload: allQueriesFromComp,
    });
  };

  const updateDropDownArray = (filteredDropDownFields) => {
    dispatch({
      type: UPDATE_DROPDOWN_ARRAY,
      payload: filteredDropDownFields,
    });
  };

  const updateRemovedDropDown = (dropDownOption) => {
    dispatch({
      type: UPDATE_REMOVED_DROPDOWN,
      payload: dropDownOption, // need to do this to stop it sticking an array within an array
    });
  };

  const updateUseOr = (updatedUseOr) => {
    console.log('useOr passed from component: ', updatedUseOr);
    dispatch({
      type: UPDATE_USE_OR,
      payload: updatedUseOr, // need to do this to stop it sticking an array within an array
    });
  };

  return (
    <AndQueryContext.Provider
      value={{
        initialQuery: state.initialQuery,
        allQueries: state.allQueries,
        dropDownFieldsInitial: state.dropDownFieldsInitial,
        dropDownFields: state.dropDownFields,
        dropDownRemoved: state.dropDownRemoved,
        useOr: state.useOr,
        loading: state.loading,
        updateAllQueries,
        updateDropDownArray,
        updateRemovedDropDown,
        updateUseOr,
      }}
    >
      {props.children}
    </AndQueryContext.Provider>
  );
};

export default AndQueryState;

Ответы [ 2 ]

0 голосов
/ 26 мая 2020

Хорошо, ответ заключался в том, что ссылки передаются из контекста, поэтому, если вы обновите что-то, взятое из контекста, независимо от того, назначили ли вы это новой константе, оригинал также обновится.

Причина, по которой я оказался в этой ситуации, была связана с плохим дизайном приложения с моей стороны из-за неопытности.

Я обошел это, перетащив запрос в файл в моей папке контекстов, JSON .stringify- его, а затем p [asing JSON. Кажется, это прерывает цепочку ссылок. Тогда я мог бы внести изменения в массивы, не затрагивая оригинал. - извиняюсь за голосование против вашего ответа - означало нажать голосование за, не заметил, и теперь он не позволит мне изменить его, пока вы его не отредактируете.

Функция, которую я использовал для внесения изменений в файл состояния выглядит следующим образом:

const prepareQueryToSend = (queryObj) => {
    const strung = JSON.stringify(queryObj);
    console.log(strung);
    const unstrung = JSON.parse(strung);
    console.log(unstrung);

    unstrung.initial.map((item, index) => {
      delete item.id;
      delete item.addDisabled;
      if (
        item.field === 'package_type' ||
        item.field === 'document_type' ||
        item.field === 'user' ||
        item.field === 'status'
      ) {
        delete item.from;
        delete item.to;
      }
      if (
        item.field === 'current_full_path' ||
        item.field === 'date' ||
        item.field === 'size'
      ) {
        delete item.selection;
      }
    });

    unstrung.OR.map((item, index) => {
      item.map((item2, index2) => {
        delete item2.id;
        delete item2.addDisabled;
        return item2;
      });

      return item;
    });

    console.log('unstrung after: ', unstrung);

    const restrung = JSON.stringify(unstrung);

    console.log(restrung);
  };
0 голосов
/ 26 мая 2020

Что ж, в соответствии с вопросом вы хотите выполнить что-то вроде этого:

list = [{name: "Jane",disabled:true},{name:"Austin", disabled: true}]

to:

newList = [{name: "Jane"},{name:"Austin"}]

Это очень просто, вы можете использовать функцию Array.map .. .

list = [{name: "Jane"},{name: "Austin"},{name:"Pearl"}];
newList = list.map((item)=>{
   // whatever you want to set;
 
return {
    name: item.name
};
})
console.log("old list:",list);
console.log("new list:",newList);

Проблема с копированием целых элементов списка в новый список заключается в том, что ссылка на каждый элемент копируется в список, а не на элемент, поэтому внесение изменений в скопированный элемент передается в оригинальный список. Вы можете обратиться к справочным материалам для большего понимания.

...