Реагировать на функциональный компонент - как считать экземпляры? - PullRequest
3 голосов
/ 26 октября 2019

Мне нужно иметь возможность отслеживать количество экземпляров моего компонента, как мне это сделать в React с использованием функциональных компонентов?

Я пытался использовать useRef(), но похоже, что он сохраняетзначение между рендерами - оно не разделяет значение между экземплярами компонента.

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

const [ ident, setIdent ] = useState(0);

useEffect(() => {
  if (document.sometring === undefined) {
    document.sometring = 0;
  } else {
    document.sometring++;
  }
  setIdent(document.sometring);
}, []);

Обновление вопроса: Вариант использования более актуален, я хочу знать, как это сделать, а не практично. Я хочу, чтобы каждый экземпляр моего независимого компонента имел уникальный последовательный идентификатор (например, «кнопка-42»), поэтому такие решения, как «дать ему случайный код», также не будут работать для меня. Глобальные менеджеры состояний, такие как redux или context, также не могут быть решением, потому что, скажем, если я с открытым исходным кодом мой компонент на GitHub, я не должен просить пользователей также установить redux или использовать React.Context. И, конечно же, этот идентификатор не должен меняться, если компонент перерисовывается.

Ответы [ 3 ]

3 голосов
/ 26 октября 2019

Вы можете использовать функцию инициализации из useState или с useEffect (если вам не нужно обновленное значение в компоненте), чтобы увеличить счетчик, и установить для initialState значениеновое значение:

/** export **/ let count = { val: 0 };

const Comp = ({ force }) => {
  // if you don't need the value inside the component on render, you can replace with useEffect(() => (count.val++, count.val), [])
  const [id] = React.useState(() => (count.val++, count.val)); 
  
  return <div>{force} Count {id}</div>;
}

const Demo = () => {
  const [force, setForce] = React.useState(0);

  return (
    <div>
      <Comp force={force} />
      <Comp force={force} />
      <Comp force={force} />
      
      <button onClick={() => setForce(force + 1)}>Force Render</button>
    </div>
  );
}

ReactDOM.render(
  <Demo />,
  root
)
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>
0 голосов
/ 26 октября 2019

Если вы хотите отслеживать количество активных компонентов в приложении (игнорируя те, которые были отрисованы ранее, но не больше)

const count = { value: 0 }
export { count }

const incrementCounter = () => count.value++
const decrementCounter = () => count.value--

// ...

useEffect(() => {
  incrementCounter();
  return decrementCounter; // will run on "unmount"
}, []); // run this only once

Конечно, если вы хотите отобразить этот счет где-то еще в приложении, которое выпотребуется сделать его реактивным - например, передать incrementCounter и decrementCounter функции счетчика поддержки и обновления где-нибудь в состоянии ваших компонентов или Redux (или оставить это на усмотрение того, кто использует этот компонент)

0 голосов
/ 26 октября 2019

Решение Redux

Dom Выход:

привет, мой идентификатор 0

привет, мой идентификатор 1

привет, мой идентификатор 2

привет, мой идентификатор 3

привет, мой идентификатор 4

Всего экземпляров: 5

Сторона реакции:

SomeTrackedComponent.js

export default const SomeTrackedComponent = ({id}) => (
   <div> hi my id is {id} </div>
)

App.js

const App = ({instances , addInstance}) =>{

  const [trackedComponents, setTrackedComponents] = useState([]);

  useEffect(()=>{
    const justSomeArray = Array.from(Array(5).keys())

    //wont have access to updated instance state within loop so initialize index
    const someJSX = justSomeArray.map((_, id = instances.currentId )=>{ 
      addInstance({ id , otherData: 'otherData?'})
      return <SomeTrackedComponent key={id} id={id} />
    })

    setTrackedComponents(someJSX)

  },[])

  return( 
    <div>
      {trackedComponents}
      Total instances: {instances.items.length}
    </div>
  )
}

export default connect(
  ({instances})=>({instances}),
  actions
)(App);

Сторона Redux:

actions.js

export const addInstance = (payload) =>(
    {type:'CREATE_INSTANCE' , payload}
)
export const removeInstance = (payload) =>(
    {type:'REMOVE_INSTANCE' , payload}
)

redurs.js

const instanceReducer = (state = { items : [] , currentId : 1} , action) => {
  switch (action.type) {
    case 'CREATE_INSTANCE':
      return {
          currentId: state.currentId + 1
          items:[...state.items , action.payload],
      }
    case 'REMOVE_INSTANCE':
      return {
          ...state,
          items: [...state.items].filter(elm => elm.id !== action.payload.id)
      }
    default:
      return state;
  }
}

export default combineReducers({
  instances: instanceReducer
})

Index.js:

// import React from 'react';
// import ReactDOM from 'react-dom';
// import { Provider } from 'react-redux';
// import { createStore  } from 'redux';
// import reducers from './redux/reducers';
// import App from './components/App';


ReactDOM.render(
    <Provider store={createStore(reducers)}>
      <App />
    </Provider>,
    document.querySelector('#root')
);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...