-
Notifications
You must be signed in to change notification settings - Fork 10
Step Component Pattern
David edited this page Sep 23, 2024
·
5 revisions
the new step components should be created in app/components/steps and remove the old component from app/components
where 'component' is the name of the step like answer.js and Component is like Answer
app/components/steps/component.js
:
export default function ComponentStep(props){
const {data, upsert}=useContext(DeliberationContext)
// fetch data from the server and upsert it into the context if/when it arrives
// before a response from the server the component should return null and not render anything
useEffect(()=>{ window.socket.emit('fetch-api-handle',p1 ,p2, ..., results=>upsert(results)),[])
function handleOnDone({valid, value, delta}){ // uses upsert, calles socket-apis ...}
// adding a new prop to onDone called delta. This is what the user had changed, either the rank or point, were as value would be all the things in a list.
// the render function should add a delta prop, this should be just the chanaged point or rank or whatever.
// The handleOndone should have code to upsert the delta into the database through an api, and into the context.
return <Component {...deriver(data, local), onDone: handleOnDone, ...props} />
}
export function Component(props){
// this is the render function, mostly what's there now
// props of the old component will need to change to match the new props define in the spread sheet - that are the output of the deriver
// stories should test this function
// it important to differentiate between props that are empty and props that are undefined. Undefined means we are waiting for the database query, so the component should not reender anything. empty, like {} or [] means the user hasen't made any entries yet. If there are undefined props, return null - don't render anything for now.
}
// in the spreadsheet each deriver has a name, but it's not necessary to use a different name since it's local to this file
export function deriver(data){
const local = useRef({}).current // keeping track of previous values in local,
// returns props for the render function, taken from data,
// being careful not to change ref's to objects that aren't different
return {}
}
app/components/steps/__tests__/component.js
:
import {deriver} from '../component.js'
...
create jest tests for the deriver
- input data undefined
- input data empty
- input data present - output data not there yet
- input data unchanged
- subset(s) of input data changes testing that only the affected part of the output has changed
stories/component.stories.js
:
- update to import and test Component, rather than ComponentStep
- update args to match the updated props of the Component
stories/component-step.stories.js
:
- import and test ComponentStep
- use the DeliberationContext decorator from comomon.js
- create mock api calls for the fetch api and action apis. See https://github.com/EnCiv/enciv-home/blob/0d5617973d1cd5c7d9f2b9d7cd5eb959c7bcaccd/stories/frequently-asked-questions.stories.js for how to mock window.socket.emit
- create tests for
- the case when the server hasn't returned data yet
- the initial (no data) use case
- the returning user case
- the case where the user enters initial data
- the case where the user updates existing data