SkillCreator in SUSI.AI used for creating new skills and Botbuilder for creating new bots had parent-child communication as seen in React components. Many components were using a state, which was lifted up to its parent and passed to its children (Design, Configure, Deploy, SkillCreator) as props. This architecture has many problems, maintainability and readability being the prime one.
For maintaining the state of SkillCreator and Botbuilder we used Redux, which lets us use global state and we don’t have to worry about passing props just for the purpose of sending data deep down. With Redux, the code size reduced and we successfully eliminated a lot of code redundancy.
Basic Data Flow in Redux
- A UI Event like onClick happens
- The UI event dispatches an action, mapDispatchToAction gives access to actions defined in action files.
- Perform synchronous or asynchronous tasks like fetching data from external API.
- The payload is used by reducer function, which updates the global store based on payload and previous state.
- The global store changes and using the mapStateToProps present, the function is subscribed to changes over time and gets the updated values of the store.
The state object consists of 3 nested objects. Each view, .i.e on botWizard, for Build tab we update the skill object. For the Design tab, design object and etc. The objective of storing in Redux store is, we require the data to persist when a user navigates/change to other tabs for example Design Tab, the data of skills tab is mapped from the store so if user switches back to skills tab, no data loss will be there. All such required fields are stored in the store.
The CREATE_SET_VIEW reducer function updates the view, e.g it can be ‘code’, ‘ui’, ‘tree’. The action setView is dispatched to update the view tab. The action setSkillData is dispatched when we want to update the skill object in our global store.Reducer function for it:
The setSkillData is called whenever the user updates the code of skills.
Updating Design Code
The setDesignData is dispatched whenever we update the code in AceEditor of design tab. generateDesignData function helps in generating design object from the designCode to update the UI view of design tab.
updateDesignData action is called for changing the design object in global state. In UIView,
In reducer, the design state is updated by extracting payload using the spread operator and adding new key-value pairs to design object.
For changing the color, handleChangeColor function in present in UIView to handle color change, which dispatches action setDesignComponentColor
The CREATE_SET_DESIGN_COMPONENT_COLOR updates the design code accordingly to match the UI changes done in the UI tab of the design view.
The reducer generates the new designCode and also sets the component color for it to be used in UI View. Similar logic is applied for handling the configured state in the reducer.
To conclude, shifting to redux architecture instead of prop drilling proved to be of great advantage. The code became more performant, modular and easy to manage. The state persisted even after component unmounted.
- Why use Redux- https://blog.logrocket.com/why-use-redux-reasons-with-clear-examples-d21bffd5835/
- Documentation of Redux – https://redux.js.org/
- React Anti-Pattern: Prop-Drilling – https://codeburst.io/react-anti-pattern-prop-drilling-54474d5236bd
- Link to the PR: https://github.com/fossasia/susi_skill_cms/pull/1978
SUSI.AI, FOSSASIA, GSoC19, Redux, Skills CMS, SUSI Chat