I am making a table on my react website with react-bootstrap-table-next (also known as react-bootstrap-table-2) and am trying to get an icon component to show up in the rows as data instead of what I have now, which is an x, like this:
A sample of what I currently have for data is:
const tools = [{key: 'Android Mobile', qual: "x"}]
But what I want to do is something like:
const tools = [{key: 'Android Mobile', qual: <CheckIcon/>}]
Where CheckIcon is const CheckIcon = () => <Icon icon={check} size={10}/> (where Icon is being imported from react-icons-kit).
Currently the entire page does not render when I do something like that, and I haven't been able to find much information on how to insert a component into an object with React. If there are any tips or tricks anyone has, that would be much appreciated!
Here is a stackblitz for anyone that wants to play around with the code
I think column.formatter can help you. there's a online demo: this
First, make sure that react-bootstrap-table-next props data accept React Component.
So far what I've found it does not support render a React Component inside the data object.
https://github.com/react-bootstrap-table/react-bootstrap-table2/blob/master/packages/react-bootstrap-table2/src/bootstrap-table.js#L118
Feel free if you want to submit a new feature at https://github.com/react-bootstrap-table/react-bootstrap-table2/issues/new
I ended up coming to the same conclusion as #Roman Masyhar and ended up taking the cheater's route for now until I end up just making my own table and just using the "✔" character in place of x's and just styling them for the same effect
In case anyone is curious I did also open a feature request here
Related
I am building a dynamic form and as of now, my component hierarchy is as follows:-
App
Caseform
DynamicFormBuilder
Context.Provider
Patients
Patient key = "patient_1"
ComponentCreator key = "patient_1_1"
Textbox
ComponentCreator key = "patient_1_2"
Textbox
ComponentCreator key = "patient_1_3"
Textbox
Patient key = "patient_2"
ComponentCreator key = "patient_2_1"
Textbox
ComponentCreator key = "patient_2_2"
Textbox
ComponentCreator key = "patient_2_3"
Textbox
As of now, I have hardcoded JSON data in caseform but eventually, it will come from the fetch call. As soon as DynamicFormBuilder receives the caseform metadata, it creates states out of it.
I am maintaining state at caseform level even for its child. I thought of doing it that way because the requirement was to support patch save(send only changed data to the backend on save button press). If anybody knows of a better way of doing this, please let me know.
I am passing in a function using context API to child components so that they can update the state in DynamicFormBuiler.
The issue I am facing is that let's say even if the user edits one textbox, the whole Dynamic form gets rendered.
I have gone through a lot of answers on StackOverflow that advise on using the shouldComponentUpdate lifecycle method, but I am not able to figure out how I will use it here.
I am adding a link to the sandbox and in the console, you can see that if a user edits a field all the things are rendered again.
CodeSandbox Link
Expected Behavior:- What I am looking for is for example:- if user-edited only one textbox say in patient 1 then only that textbox gets re-rendered again
This is my first time using react. I apologize in advance if someone feels I have not done enough research, I have read through a lot of questions but still facing some challenges, any help will be really appreciated.
If you wrap each component in the React.memo() HOC, this should prevent excessive rerenders.
https://reactjs.org/docs/react-api.html#reactmemo
-Edit-
Yes it works with class components too.
e.g.
const MyComponent = React.memo(class extends React.Component {
render () {
return <h1>TEST</h1>
}
});
I have a very large and complex React application. It is designed to behave like a desktop application. The interface is a document style interface with tabs, each tab can be one of many different type of editor component (there are currently 14 different editor screens). It is possible to have a very large number of tabs open at once (20-30 tabs). The application was originally written all with React class components, but with newer components (and where significant refactors have been required) I've moved to functional components using hooks. I prefer the concise syntax of functions and that seems to be the recommended direction to take in general, but I've encountered a pattern from the classes that I don't know how to replicate with functions.
Basically, each screen (tab) on the app is an editor of some sort (think Microsoft office, but where you can have a spreadsheet, text document, vector image, Visio diagram, etc all in tabs within the same application... Because each screen is so distinct they manage their own internal state. I don't think Redux or anything like that is a good solution here because the amount of individually owned bits of state are so complex. Each screen needs to be able to save it's current working document to the database, and typically provides a save option. Following standard object oriented design the 'save' function is implemented as a method on the top level component for each editor. However I need to perform a 'save-all' function where I iterate through all of the open tabs and call the save method (using a reference) on each of the tabs. Something like:
openTabs.forEach((tabRef) => tabRef.current.save());
So, If I make this a functional component then I have my save method as a function assigned to a constant inside the function:
const save = () => {...}
But how can I call that from a parent? I think the save for each component should live within that component, not at a higher level. Aside from the fact that would make it very difficult to find and maintain, it also would break my modular loading which only loads the component when needed as the save would have to be at a level above the code-splitting.
The only solution to this problem that I can think of is to have a save prop on the component and a useEffect() to call the save when that save prop is changed - then I'd just need to write a dummy value of anything to that save prop to trigger a save... This seems like a very counter-intuitive and overly complex way to do it.... Or do I simply continue to stick with classes for these components?
Thankyou,
Troy
But how can I call that from a parent? I think the save for each component should live within that component, not at a higher level.
You should ask yourself if the component should be smart vs dumb (https://www.digitalocean.com/community/tutorials/react-smart-dumb-components).
Consider the following:
const Page1 = ({ onSave }) => (...);
const Page2 = ({ onSave }) => (...);
const App = () => {
const handleSavePage1 = (...) => { ... };
const handleSavePage2 = (...) => { ... };
const handleSaveAll = (...) => {
handleSavePage1();
handleSavePage2();
};
return (
<Page1 onSave={handleSavePage1} />
<Page2 onSave={handleSavePage2} />
<Button onClick={handleSaveAll}>Save all</button>
);
};
You've then separated the layout from the functionality, and can compose the application as needed.
I don't think Redux or anything like that is a good solution here because the amount of individually owned bits of state are so complex.
I don't know if for some reason Redux is totally out of the picture or not, but I think it's one of the best options in a project like this.
Where you have a separated reducer for each module, managing the module's state, also each reducer having a "saveTabX" action, all of them available to be dispatched in the Root component.
I have a very large list of 'nested' data and I had to use 4 maps to extract all data and display it
the problem is when I click to redirect to this page it stuck for like half a second or sometimes more before even rendering the page
is there any solution on how to place a loader until this map finish extracting data
something like :
return (
{ 'map is still in progress'? <LoaderComponent/> : <ShowResult/>}
)
I tried something like the previous code and it shows the loader but it didn't even start to map
For large/expensive lists the best practice would be to use the hook useMemo
you can read more about it https://reactjs.org/docs/hooks-reference.html#usememo
implemented as
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
the second argument being an array of dependencies, e.g. page number, keyPress values, etc.
but in your case you could just use
const memoizedValue = useMemo(() => _hugeArray, []);
and then map the memoizedValue in your template
{memoizedValue.map(el, i)=> <div key={i}>{el}</div>}
Note that any function passed to useMemo runs during rendering. Restrict side effects to your useEffect hook
There's not much you can really do. In a scenario where you need to render a large list of items I'd recommend you check out react window. It was written by a developer who contributed to React and it helps when rendering large lists by only rendering the items that are in the viewport.
I would add a quick implementation to my answer but I don't know what the components of your app look like.
I'm writing some tests for a React app using Testing Library. I want to check that some text appears, but I need to check it appears in a particular place because I know it already appears somewhere else.
The Testing Library documentation for queries says that the getByText query takes a container parameter, which I guessed lets you search within that container. I tried doing this, with the container and text parameters in the order specified in the docs:
const container = getByTestId('my-test-id');
expect(getByText(container, 'some text')).toBeTruthy();
and I get an error: matcher.test is not a function.
If I put the params the other way round:
const container = getByTestId('my-test-id');
expect(getByText('some text', container)).toBeTruthy();
I get a different error: Found multiple elements with the text: some text
Which means it's not searching inside the specified container.
I think I'm not understanding how getByText works. What am I doing wrong?
Better to use within for this sort of things:
render(<MyComponent />)
const { getByText } = within(screen.getByTestId('my-test-id'))
expect(getByText('some text')).toBeInTheDocument()
Another way to do this
import {render, screen} from '#testing-library/react';
...
render(<MyComponent />);
expect(screen.getByTestId('my-test-id')).toHaveTextContent('some text');
Note it is now recommended to use screen instead of the results of render.
(StackOverflow post the points to a KC Dobbs Article explaining why: react-testing-library - Screen vs Render queries)
This way you can be more precise, focusing in specific item:
expect(queryByTestId("helperText")?.textContent).toContain("Help me!");
Should an element's text contents be tested, or only the visibility thereof? I think this is a question of what is an implementation detail.
Example:
it('renders post body', async () => {
getPost.resolves(fakePost)
const { getByTestId } = render(<Post />)
await wait(() => getByTestId('post-body'))
expect(getByTestId('post-body')).toBeVisible()
// Should this next line be included?
expect(getByTestId('post-body')).toHaveTextContent(fakePost.body)
})
I feel like it is an implementation detail regarding how the body text is rendered, that I should only care that something was rendered.
For example, I next I want to store the body text as markdown and render it as HTML. To implement this, I must first change the test, because no longer will the stored text be equal to what is rendered in the DOM.
However, if only testing the visibility of a rendered element, there is no guarantee that element actually contains anything. I feel the test should be safer than that.
expect(getByTestId('post-body')).not.toBeEmpty() comes to mind in the jest-dom api, but that would pass even if the element contained only another element with no actual text contents.
Especially thanks to the guiding principals, I think it’s fair to say if you are testing your component or app the same way you would instruct a human to test it in production, then you are doing it right.
If your component is taking an API call, and formatting it into Markdown, then you should test that it is actually happening correctly. How the component is rendering (and mimicking it in your test) is an example of testing implementation details. Testing what the component renders is not.
I know it’s a fine line, but I think you should include your last line. I also think it’d be great if you could find a way to query by something other than test-id.